diff --git a/js/angular/controller/navViewController.js b/js/angular/controller/navViewController.js index bb7af55ab5..9a8ce5704f 100644 --- a/js/angular/controller/navViewController.js +++ b/js/angular/controller/navViewController.js @@ -12,6 +12,7 @@ IonicModule function($scope, $element, $attrs, $compile, $controller, $ionicNavBarDelegate, $ionicNavViewDelegate, $ionicHistory, $ionicViewSwitcher) { var DATA_ELE_IDENTIFIER = '$eleId'; + var DATA_DESTROY_ELE = '$destroyEle'; var VIEW_STATUS_ACTIVE = 'active'; var VIEW_STATUS_CACHED = 'cached'; var HISTORY_AFTER_ROOT = 'after-root'; @@ -41,6 +42,8 @@ function($scope, $element, $attrs, $compile, $controller, $ionicNavBarDelegate, var deregisterInstance = $ionicNavViewDelegate._registerInstance(self, $attrs.delegateHandle); $scope.$on('$destroy', deregisterInstance); + $scope.$on('$ionicHistory.deselect', self.cacheCleanup); + return viewData; }; @@ -159,6 +162,16 @@ function($scope, $element, $attrs, $compile, $controller, $ionicNavBarDelegate, }; + self.cacheCleanup = function() { + var viewElements = $element.children(); + for (var x = 0, l = viewElements.length; x < l; x++) { + if (viewElements.eq(x).data(DATA_DESTROY_ELE)) { + $ionicViewSwitcher.destroyViewEle(viewElements.eq(x)); + } + } + }; + + self.clearCache = function() { var viewElements = $element.children(); var viewElement, viewScope; diff --git a/js/angular/controller/tabsController.js b/js/angular/controller/tabsController.js index f6d0a4a275..f98c0af98b 100644 --- a/js/angular/controller/tabsController.js +++ b/js/angular/controller/tabsController.js @@ -45,6 +45,7 @@ function($scope, $ionicHistory, $element) { _selectedTab = null; tab.$tabSelected = false; (tab.onDeselect || angular.noop)(); + tab.$broadcast && tab.$broadcast('$ionicHistory.deselect'); } }; diff --git a/test/unit/angular/directive/navView.unit.js b/test/unit/angular/directive/navView.unit.js index 27945e2e48..721baf1887 100644 --- a/test/unit/angular/directive/navView.unit.js +++ b/test/unit/angular/directive/navView.unit.js @@ -102,8 +102,49 @@ describe('Ionic nav-view', function() { ionViewCacheFalsePropertyState = { template: 'ionViewCacheFalsePropertyState', cache: false - }; - + }, + tabAbstractState = { + abstract: true, + views: { + 'root': { + template: '' + + '' + + '' + + '' + + '

Inline Tab

' + + '
' + } + } + }, + tab1page1State = { + views: { + 'tab1': { + template: 'tab1page1' + } + } + }, + tab2page1State = { + views: { + 'tab2': { + template: 'tab2page1' + } + } + }, + tab3page1State = { + views: { + 'tab3': { + template: 'tab3page1' + } + } + }, + tab3page2NoCacheState = { + cache: false, + views: { + 'tab3': { + template: 'tab3page2NoCache' + } + } + } beforeEach(module(function ($stateProvider) { $stateProvider .state('a', aState) @@ -128,7 +169,12 @@ describe('Ionic nav-view', function() { .state('ionView1', ionView1State) .state('ionView2', ionView2State) .state('ionViewCacheFalseAttr', ionViewCacheFalseAttrState) - .state('ionViewCacheFalseProperty', ionViewCacheFalsePropertyState); + .state('ionViewCacheFalseProperty', ionViewCacheFalsePropertyState) + .state('tabAbstract', tabAbstractState) + .state('tabAbstract.tab1page1', tab1page1State) + .state('tabAbstract.tab2page1', tab2page1State) + .state('tabAbstract.tab3page1', tab3page1State) + .state('tabAbstract.tab3page2', tab3page2NoCacheState); })); beforeEach(inject(function(_$compile_, $ionicConfig, $rootScope) { @@ -901,6 +947,70 @@ describe('Ionic nav-view', function() { expect(divs.eq(0).text()).toBe('page2'); })); + it('should create and cache tabs', inject(function ($state, $q, $timeout, $compile, $ionicConfig) { + elem.append($compile('')(scope)); + + $state.go(tab1page1State); + $q.flush(); + $timeout.flush(); + + var tab1Ele = elem[0].querySelector('ion-nav-view[name="tab1"]'); + expect(tab1Ele.getAttribute('nav-view')).toBe('active'); + + $state.go(tab2page1State); + $q.flush(); + $timeout.flush(); + + var tab2Ele = elem[0].querySelector('ion-nav-view[name="tab2"]'); + expect(tab1Ele.getAttribute('nav-view')).toBe('cached'); + expect(tab2Ele.getAttribute('nav-view')).toBe('active'); + + $state.go(tab3page1State); + $q.flush(); + $timeout.flush(); + + var tab3Ele = elem[0].querySelector('ion-nav-view[name="tab3"]'); + expect(tab1Ele.getAttribute('nav-view')).toBe('cached'); + expect(tab2Ele.getAttribute('nav-view')).toBe('cached'); + expect(tab3Ele.getAttribute('nav-view')).toBe('active'); + + $state.go(tab1page1State); + $q.flush(); + $timeout.flush(); + + expect(tab1Ele.getAttribute('nav-view')).toBe('active'); + expect(tab2Ele.getAttribute('nav-view')).toBe('cached'); + expect(tab3Ele.getAttribute('nav-view')).toBe('cached'); + })); + + it('should not cache a tab with cache false state property', inject(function ($state, $q, $timeout, $compile, $ionicConfig) { + elem.append($compile('')(scope)); + + $state.go(tab3page2NoCacheState); + $q.flush(); + $timeout.flush(); + $timeout.flush(); + + var tab3NoCacheEle = elem[0].querySelector('ion-nav-view[name="tab3"]'); + expect(tab3NoCacheEle.getAttribute('nav-view')).toBe('active'); + + var tab3InnerEle = tab3NoCacheEle.querySelector('[nav-view="active"]'); + expect(tab3InnerEle.innerText).toEqual('tab3page2NoCache'); + + $state.go(tab1page1State); + $q.flush(); + $timeout.flush(); + $timeout.flush(); + + var tab1Ele = elem[0].querySelector('ion-nav-view[name="tab1"]'); + expect(tab3NoCacheEle.getAttribute('nav-view')).toBe('cached'); + expect(tab1Ele.getAttribute('nav-view')).toBe('active'); + expect(tab1Ele.innerText).toEqual('tab1page1'); + + tab3InnerEle = tab3NoCacheEle.querySelector('[nav-view="active"]'); + expect(tab3InnerEle).toBe(null); + })); + }); angular.module('ngMock').config(function ($provide) {