refactor(ionNavButtons): compile in the correct context

This commit is contained in:
Andy Joslin
2014-03-21 09:09:34 -05:00
parent 6d403efb48
commit f083eaf7f7
6 changed files with 69 additions and 92 deletions

View File

@@ -1,67 +0,0 @@
describe('ionNavButtons directive', function() {
beforeEach(module('ionic.ui.navBar'));
function setup(attrs, contents) {
var el;
inject(function($compile, $rootScope) {
el = angular.element('<ion-nav-buttons ' + (attrs||'') + '>'+(contents||'')+'</ion-nav-buttons>');
el.data('$ionNavBarController', {
leftButtonsElement: angular.element('<div>'),
rightButtonsElement: angular.element('<div>')
});
el = $compile(el)($rootScope.$new());
$rootScope.$apply();
});
return el;
}
it('should error without parent navBar', inject(function($compile, $rootScope) {
expect(function() {
$compile('<ion-nav-buttons>')($rootScope.$new());
}).toThrow();
}));
it('should make the container element end up display:none', function() {
var el = setup();
expect(el.css('display')).toBe('none');
});
it('should transclude contents into left', function() {
var el = setup('side="left" ng-init="items=[1,2]"', '<button ng-repeat="i in items">{{i}}</button>');
var leftButtons = el.controller('ionNavBar').leftButtonsElement.children();
expect(leftButtons.text().trim()).toEqual('12');
el.scope().$apply('items=[1,3,5]');
expect(leftButtons.text().trim()).toEqual('135');
});
it('should transclude contents into right', function() {
var el = setup('side="right" ng-init="items=[1,2]"', '<button ng-repeat="i in items">{{i}}</button>');
var rightButtons = el.controller('ionNavBar').rightButtonsElement.children();
expect(rightButtons.text().trim()).toEqual('12');
el.scope().$apply('items=[1,3,5]');
expect(rightButtons.text().trim()).toEqual('135');
});
it('left should destroy contents on scope destroy', inject(function($animate) {
spyOn($animate, 'leave');
var el = setup('side="left" ng-init="items=[1,2]"', '<button ng-repeat="i in items">{{i}}</button>');
var leftButtons = el.controller('ionNavBar').leftButtonsElement.children();
expect(leftButtons.text().trim()).toEqual('12');
el.scope().$destroy();
expect($animate.leave).toHaveBeenCalled();
expect($animate.leave.mostRecentCall.args[0][0]).toBe(leftButtons[0]);
}));
it('right should destroy contents on scope destroy', inject(function($animate) {
spyOn($animate, 'leave');
var el = setup('side="right" ng-init="items=[1,2]"', '<button ng-repeat="i in items">{{i}}</button>');
var rightButtons = el.controller('ionNavBar').rightButtonsElement.children();
expect(rightButtons.text().trim()).toEqual('12');
el.scope().$destroy();
expect($animate.leave).toHaveBeenCalled();
expect($animate.leave.mostRecentCall.args[0][0]).toBe(rightButtons[0]);
}));
});

View File

@@ -381,6 +381,7 @@ function($ionicViewService, $rootScope, $animate, $compile, $parse) {
require: '^ionNavBar',
restrict: 'E',
compile: function($element, $attrs) {
var content = $element.contents().remove();
return function($scope, $element, $attrs, navBarCtrl) {
var navElement = $attrs.side === 'right' ?
navBarCtrl.rightButtonsElement :
@@ -390,7 +391,14 @@ function($ionicViewService, $rootScope, $animate, $compile, $parse) {
//so we can remove them all when this element dies -
//even if the buttons have changed through an ng-repeat or the like,
//we just remove their div parent and they are gone.
var buttons = angular.element('<div>').append($element.contents().remove());
var buttons = angular.element('<div>').append(content);
//Compile buttons inside content so they have access to everything
//something inside content does (eg parent ionicScroll)
$element.append(buttons);
$compile(buttons)($scope);
//Append buttons to navbar
$animate.enter(buttons, navElement);
//When our ion-nav-buttons container is destroyed,

View File

@@ -40,11 +40,6 @@ angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gestu
restrict: 'EA',
priority: 1000,
require: '^?ionNavBar',
scope: {
title: '@',
hideBackButton: '&',
hideNavBar: '&',
},
compile: function(tElement, tAttrs, transclude) {
tElement.addClass('pane');
tElement[0].removeAttribute('title');
@@ -53,18 +48,21 @@ angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gestu
if (!navBarCtrl) {
return;
}
navBarCtrl.changeTitle($scope.title, $scope.$parent.$navDirection);
navBarCtrl.changeTitle($attr.title, $scope.$navDirection);
// Should we hide a back button when this tab is shown
navBarCtrl.showBackButton(!$scope.hideBackButton());
$scope.$watch($attr.hideBackButton, function(value) {
// Should we hide a back button when this tab is shown
navBarCtrl.showBackButton(!value);
});
// Should the nav bar be hidden for this view or not?
navBarCtrl.showBar(!$scope.hideNavBar());
$scope.$watch($attr.hideNavBar, function(value) {
// Should the nav bar be hidden for this view or not?
navBarCtrl.showBar(!value);
});
// watch for changes in the title
$scope.$watch('title', function(val, oldVal) {
//Don't send in initial value, changeTitle does that
if (val !== oldVal) {
$attr.$observe('title', function(val, oldVal) {
if (val) {
navBarCtrl.setTitle(val);
}
});

View File

@@ -1,5 +1,15 @@
describe('ionNavBackButton directive', function() {
beforeEach(module('ionic'));
beforeEach(module('ionic', function($compileProvider) {
$compileProvider.directive('needsScroll', function() {
return {
//Test if the buttons are 'children of ionScroll' when compiled
require: '^$ionicScroll',
link: function(scope, element, attrs, ctrl) {
element.data('scrollCtrl', ctrl);
}
};
});
}));
function setup(attr, content) {
var el;
@@ -14,6 +24,27 @@ describe('ionNavBackButton directive', function() {
return el;
}
it('should compile buttons with same scope & access the same data on compile', inject(function($compile, $rootScope) {
var el = $compile('<div>' +
'<ion-nav-bar></ion-nav-bar>' +
'<ion-view>' +
'<ion-content>' +
'<ion-nav-buttons side="left">' +
'<button needs-scroll>Hello!</button>' +
'</ion-nav-buttons>' +
'</ion-content>' +
'</ion-view>' +
'</div>')($rootScope.$new());
$rootScope.$apply();
expect(el.find('ion-content').children().scope())
.toBe(el.find('.left-buttons button').scope());
//Test if the button was compiled able to access the parents of ion-nav-buttons
var scrollCtrl = el.find('ion-content').controller('$ionicScroll');
expect(scrollCtrl).toBeTruthy();
expect(el.find('button[needs-scroll]').data('scrollCtrl')).toBe(scrollCtrl);
}));
it('should error without a parent ionNavBar', inject(function($compile, $rootScope) {
expect(function() {
$compile('<ion-nav-back-button>')($rootScope);

View File

@@ -40,24 +40,27 @@ describe('ionView directive', function() {
expect(el.controller('ionNavBar').changeTitle).toHaveBeenCalledWith('Hi, 1!', 'foo');
});
it('should showBackButten depending on what is given', function() {
var el = setup();
it('should showBackButton depending on what is given', function() {
var el = setup('hide-back-button="shouldHideBack"');
expect(el.controller('ionNavBar').showBackButton).toHaveBeenCalledWith(true);
el = setup('hide-back-button="true"');
el.scope().$apply('shouldHideBack = true');
expect(el.controller('ionNavBar').showBackButton).toHaveBeenCalledWith(false);
el.scope().$apply('shouldHideBack = false');
expect(el.controller('ionNavBar').showBackButton).toHaveBeenCalledWith(true);
});
it('should showBar depending on what is given', function() {
var el = setup();
var el = setup('hide-nav-bar="shouldHide"');
expect(el.controller('ionNavBar').showBar).toHaveBeenCalledWith(true);
var el = setup('hide-nav-bar="true"');
el.scope().$apply('shouldHide = true');
expect(el.controller('ionNavBar').showBar).toHaveBeenCalledWith(false);
el.scope().$apply('shouldHide = false');
expect(el.controller('ionNavBar').showBar).toHaveBeenCalledWith(true);
});
it('should setTitle on change', function() {
var el = setup('', {title: 'foo'});
expect(el.controller('ionNavBar').setTitle).not.toHaveBeenCalled();
el.isolateScope().$apply('title = "bar"');
expect(el.controller('ionNavBar').setTitle).toHaveBeenCalledWith('bar');
var el = setup('title="{{something}}1"');
el.scope().$apply('something = "bar"');
expect(el.controller('ionNavBar').setTitle).toHaveBeenCalledWith('bar1');
});
});

View File

@@ -24,7 +24,7 @@
<ion-view title="Sign-In">
<ion-nav-buttons side="left">
<button class="button button-icon icon ion-home">
<button class="button button-icon icon ion-home" ng-click="foo()">
Home
</button>
</ion-nav-buttons>
@@ -321,6 +321,10 @@
})
.controller('SignInCtrl', function($scope, $state) {
$scope.foo = function() {
alert('foo');
};
$scope.signIn = function(user) {
$state.go('tabs.autolist');
};