Skip to content

Commit ecfdbaa

Browse files
committed
fix(ionTabs): do not pre-transclude; stops error on compile
Closes #730
1 parent 9cfd95f commit ecfdbaa

File tree

2 files changed

+59
-43
lines changed

2 files changed

+59
-43
lines changed

Diff for: js/ext/angular/src/directive/ionicTabBar.js

+27-26
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ function($scope, $ionicViewService, $rootScope, $element) {
144144
}])
145145

146146
// Generic controller directive
147-
.directive('ionTab', ['$rootScope', '$animate', '$ionicBind', '$compile', '$ionicViewService', function($rootScope, $animate, $ionicBind, $compile, $ionicViewService) {
147+
.directive('ionTab', ['$rootScope', '$animate', '$ionicBind', '$compile', '$ionicViewService',
148+
function($rootScope, $animate, $ionicBind, $compile, $ionicViewService) {
148149

149150
//Returns ' key="value"' if value exists
150151
function attrStr(k,v) {
@@ -154,10 +155,17 @@ function($scope, $ionicViewService, $rootScope, $element) {
154155
restrict: 'E',
155156
require: ['^ionTabs', 'ionTab'],
156157
replace: true,
157-
transclude: 'element',
158158
controller: '$ionicTab',
159159
scope: true,
160-
compile: function(element, attr, transclude) {
160+
compile: function(element, attr) {
161+
//Do we have a navView?
162+
var navView = element[0].querySelector('ion-nav-view') ||
163+
element[0].querySelector('data-ion-nav-view');
164+
var navViewName = navView && navView.getAttribute('name');
165+
166+
//Remove the contents of the element so we can compile them later, if tab is selected
167+
var tabContent = angular.element('<div class="pane">')
168+
.append( element.contents().remove() );
161169
return function link($scope, $element, $attr, ctrls) {
162170
var childScope, childElement, tabNavElement;
163171
tabsCtrl = ctrls[0],
@@ -174,6 +182,19 @@ function($scope, $ionicViewService, $rootScope, $element) {
174182
href: '@',
175183
});
176184

185+
tabsCtrl.add($scope);
186+
$scope.$on('$destroy', function() {
187+
tabsCtrl.remove($scope);
188+
tabNavElement.isolateScope().$destroy();
189+
tabNavElement.remove();
190+
});
191+
192+
if (navViewName) {
193+
$scope.navViewName = navViewName;
194+
$scope.$on('$stateChangeSuccess', selectTabIfMatchesState);
195+
selectTabIfMatchesState();
196+
}
197+
177198
tabNavElement = angular.element(
178199
'<ion-tab-nav' +
179200
attrStr('title', attr.title) +
@@ -188,13 +209,6 @@ function($scope, $ionicViewService, $rootScope, $element) {
188209
tabNavElement.data('$ionTabController', tabCtrl);
189210
tabsCtrl.$tabsElement.append($compile(tabNavElement)($scope));
190211

191-
tabsCtrl.add($scope);
192-
$scope.$on('$destroy', function() {
193-
tabsCtrl.remove($scope);
194-
tabNavElement.isolateScope().$destroy();
195-
tabNavElement.remove();
196-
});
197-
198212
$scope.$watch('$tabSelected', function(value) {
199213
if (!value) {
200214
$scope.$broadcast('tab.hidden', $scope);
@@ -205,26 +219,13 @@ function($scope, $ionicViewService, $rootScope, $element) {
205219
childElement = null;
206220
if (value) {
207221
childScope = $scope.$new();
208-
transclude(childScope, function(clone) {
209-
//remove title attr to stop hover annoyance!
210-
clone[0].removeAttribute('title');
211-
$animate.enter(clone, tabsCtrl.$element);
212-
clone.addClass('pane');
213-
childElement = clone;
214-
});
222+
childElement = tabContent.clone();
223+
$animate.enter(childElement, tabsCtrl.$element);
224+
$compile(childElement)(childScope);
215225
$scope.$broadcast('tab.shown', $scope);
216226
}
217227
});
218228

219-
transclude($scope, function(clone) {
220-
var navView = clone[0].querySelector('ion-nav-view');
221-
if (navView) {
222-
$scope.navViewName = navView.getAttribute('name');
223-
selectTabIfMatchesState();
224-
$scope.$on('$stateChangeSuccess', selectTabIfMatchesState);
225-
}
226-
});
227-
228229
function selectTabIfMatchesState() {
229230
// this tab's ui-view is the current one, go to it!
230231
if ($ionicViewService.isCurrentStateNavView($scope.navViewName)) {

Diff for: js/ext/angular/test/directive/ionicTabBar.unit.js

+32-17
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ describe('tabs', function() {
244244
beforeEach(module('ionic'));
245245
var tabsCtrl, tabsEl, scope;
246246
function setup(attrs, content) {
247-
inject(function($compile, $rootScope, $injector) {
247+
inject(function($compile, $rootScope) {
248248
tabsEl = angular.element('<ion-tabs><ion-tab '+(attrs||'')+'>'+(content||'')+'</ion-tab></ion-tabs>');
249249

250250
$compile(tabsEl)($rootScope.$new());
@@ -256,6 +256,19 @@ describe('tabs', function() {
256256
spyOn(tabsCtrl, 'remove');
257257
});
258258
}
259+
260+
it('should not initially compile content until selected', inject(function($compile, $rootScope) {
261+
var el = $compile('<ion-tabs>' +
262+
'<ion-tab></ion-tab>' +
263+
'<ion-tab><div ng-init="$root.elephant = \'banana\'"></div></ion-tab>' +
264+
'</ion-tabs>')($rootScope);
265+
$rootScope.$apply();
266+
expect($rootScope.elephant).toBeUndefined();
267+
el.controller('ionTabs').select(1);
268+
$rootScope.$apply();
269+
expect($rootScope.elephant).toBe('banana');
270+
}));
271+
259272

260273
it('should add itself to tabsCtrl and remove on $destroy', function() {
261274
var el = setup();
@@ -292,26 +305,28 @@ describe('tabs', function() {
292305
expect(tabsCtrl.tabs[0].navViewName).toBeUndefined();
293306
});
294307

295-
it('should set navViewName and select when necessary if a child nav-view', inject(function($ionicViewService, $rootScope) {
296-
var isCurrent = false;
297-
spyOn($ionicViewService, 'isCurrentStateNavView').andCallFake(function(name) {
298-
return isCurrent;
299-
});
308+
angular.forEach(['ion-nav-view', 'data-ion-nav-view'], function(directive) {
309+
it('should set navViewName and select when necessary if a child '+directive, inject(function($ionicViewService, $rootScope) {
310+
var isCurrent = false;
311+
spyOn($ionicViewService, 'isCurrentStateNavView').andCallFake(function(name) {
312+
return isCurrent;
313+
});
300314

301-
setup('', '<ion-nav-view name="banana"></ion-nav-view>');
302-
spyOn(tabsCtrl, 'select');
303-
var tab = tabsCtrl.tabs[0];
315+
setup('', '<' + directive + ' name="banana"></' + directive + '>');
316+
spyOn(tabsCtrl, 'select');
317+
var tab = tabsCtrl.tabs[0];
304318

305-
expect(tab.navViewName).toBe('banana');
306-
expect($ionicViewService.isCurrentStateNavView).toHaveBeenCalledWith('banana');
319+
expect(tab.navViewName).toBe('banana');
320+
expect($ionicViewService.isCurrentStateNavView).toHaveBeenCalledWith('banana');
307321

308-
$ionicViewService.isCurrentStateNavView.reset();
309-
isCurrent = true;
310-
$rootScope.$broadcast('$stateChangeSuccess');
322+
$ionicViewService.isCurrentStateNavView.reset();
323+
isCurrent = true;
324+
$rootScope.$broadcast('$stateChangeSuccess');
311325

312-
expect($ionicViewService.isCurrentStateNavView).toHaveBeenCalledWith('banana');
313-
expect(tabsCtrl.select).toHaveBeenCalledWith(tab);
314-
}));
326+
expect($ionicViewService.isCurrentStateNavView).toHaveBeenCalledWith('banana');
327+
expect(tabsCtrl.select).toHaveBeenCalledWith(tab);
328+
}));
329+
});
315330

316331
it('should transclude on $tabSelected=true', function() {
317332
setup('', '<div class="inside-content"></div>');

0 commit comments

Comments
 (0)