diff --git a/js/angular/directive/view.js b/js/angular/directive/view.js
index 227d92903b..f4a8004da8 100644
--- a/js/angular/directive/view.js
+++ b/js/angular/directive/view.js
@@ -34,28 +34,56 @@
*
* ```
*
- ## View LifeCycle and Events
-
- Views can be cached, which means *controllers normally only load once*, which may
- affect your controller logic. To know when a view has entered or left, events
- have been added that are emitted from the view's scope. These events also
- contain data about the view, such as the title and whether the back button should
- show. Also contained is transition data, such as the transition type and
- direction that will be or was used.
-
- * `$ionicView.loaded`: The view has loaded. This event only happens once per
- view being created and added to the DOM. If a view leaves but is cached,
- then this event will not fire again on a subsequent viewing. The loaded event
- is good place to put your setup code for the view; however, it is not the
- recommended event to listen to when a view becomes active.
- * `$ionicView.enter`: The view has fully entered and is now the active view.
- This event will fire, whether it was the first load or a cached view.
- * `$ionicView.leave`: The view has finished leaving and is no longer the
- active view. This event will fire, whether it is cached or destroyed.
- * `$ionicView.beforeEnter`: The view is about to enter and become the active view.
- * `$ionicView.beforeLeave`: The view is about to leave and no longer be the active view.
- * `$ionicView.afterEnter`: The view has fully entered and is now the active view.
- * `$ionicView.afterLeave`: The view has finished leaving and is no longer the active view.
+ * ## View LifeCycle and Events
+ *
+ * Views can be cached, which means *controllers normally only load once*, which may
+ * affect your controller logic. To know when a view has entered or left, events
+ * have been added that are emitted from the view's scope. These events also
+ * contain data about the view, such as the title and whether the back button should
+ * show. Also contained is transition data, such as the transition type and
+ * direction that will be or was used.
+ *
+ *
+ *
+ * $ionicView.loaded |
+ * The view has loaded. This event only happens once per
+ * view being created and added to the DOM. If a view leaves but is cached,
+ * then this event will not fire again on a subsequent viewing. The loaded event
+ * is good place to put your setup code for the view; however, it is not the
+ * recommended event to listen to when a view becomes active. |
+ *
+ *
+ * $ionicView.enter |
+ * The view has fully entered and is now the active view.
+ * This event will fire, whether it was the first load or a cached view. |
+ *
+ *
+ * $ionicView.leave |
+ * The view has finished leaving and is no longer the
+ * active view. This event will fire, whether it is cached or destroyed. |
+ *
+ *
+ * $ionicView.beforeEnter |
+ * The view is about to enter and become the active view. |
+ *
+ *
+ * $ionicView.beforeLeave |
+ * The view is about to leave and no longer be the active view. |
+ *
+ *
+ * $ionicView.afterEnter |
+ * The view has fully entered and is now the active view. |
+ *
+ *
+ * $ionicView.afterLeave |
+ * The view has finished leaving and is no longer the active view. |
+ *
+ *
+ * $ionicView.unloaded |
+ * The view's controller has been destroyed and its element has been
+ * removed from the DOM. |
+ *
+ *
*
* ## Caching
*
diff --git a/js/angular/service/viewSwitcher.js b/js/angular/service/viewSwitcher.js
index 197fb63950..9ab2c45a7d 100644
--- a/js/angular/service/viewSwitcher.js
+++ b/js/angular/service/viewSwitcher.js
@@ -19,6 +19,7 @@ function($timeout, $document, $q, $ionicClickBlock, $ionicConfig, $ionicNavBarDe
var DATA_ELE_IDENTIFIER = '$eleId';
var DATA_VIEW_ACCESSED = '$accessed';
var DATA_FALLBACK_TIMER = '$fallbackTimer';
+ var DATA_VIEW = '$viewData';
var NAV_VIEW_ATTR = 'nav-view';
var HISTORY_CURSOR_ATTR = 'history-cursor';
var VIEW_STATUS_ACTIVE = 'active';
@@ -33,68 +34,6 @@ function($timeout, $document, $q, $ionicClickBlock, $ionicConfig, $ionicNavBarDe
var cachedAttr = ionic.DomUtil.cachedAttr;
var transitionPromises = [];
- function getViewElementIdentifier(locals, view) {
- if (viewState(locals).abstract) return viewState(locals).name;
- if (view) return view.stateId || view.viewId;
- return ionic.Utils.nextUid();
- }
-
- function viewState(locals) {
- return locals && locals.$$state && locals.$$state.self || {};
- }
-
- function getTransitionData(viewLocals, enteringEle, direction, view) {
- // Priority
- // 1) attribute directive on the button/link to this view
- // 2) entering element's attribute
- // 3) entering view's $state config property
- // 4) view registration data
- // 5) global config
- // 6) fallback value
-
- var state = viewState(viewLocals);
- var viewTransition = nextTransition || cachedAttr(enteringEle, 'view-transition') || state.viewTransition || $ionicConfig.views.transition() || 'ios';
- var navBarTransition = $ionicConfig.navBar.transition();
- direction = nextDirection || cachedAttr(enteringEle, 'view-direction') || state.viewDirection || direction || 'none';
-
- return extend(getViewData(view), {
- transition: viewTransition,
- navBarTransition: navBarTransition === 'view' ? viewTransition : navBarTransition,
- direction: direction,
- shouldAnimate: (viewTransition !== 'none' && direction !== 'none')
- });
- }
-
- function getViewData(view) {
- view = view || {};
- return {
- viewId: view.viewId,
- historyId: view.historyId,
- stateId: view.stateId,
- stateName: view.stateName,
- stateParams: view.stateParams
- };
- }
-
- function navViewAttr(ele, value) {
- if (arguments.length > 1) {
- cachedAttr(ele, NAV_VIEW_ATTR, value);
- } else {
- return cachedAttr(ele, NAV_VIEW_ATTR);
- }
- }
-
- function destroyViewEle(ele) {
- // we found an element that should be removed
- // destroy its scope, then remove the element
- if (ele && ele.length) {
- var viewScope = ele.scope();
- viewScope && viewScope.$destroy();
- ele.remove();
- }
- }
-
-
var ionicViewSwitcher = {
create: function(navViewCtrl, viewLocals, enteringView, leavingView) {
@@ -176,6 +115,13 @@ function($timeout, $document, $q, $ionicClickBlock, $ionicConfig, $ionicNavBarDe
var transitionFn = $ionicConfig.transitions.views[enteringData.transition] || $ionicConfig.transitions.views.none;
transitionFn(enteringEle, null, enteringData.direction, true).run(0);
+ enteringEle.data(DATA_VIEW, {
+ viewId: enteringData.viewId,
+ historyId: enteringData.historyId,
+ stateName: enteringData.stateName,
+ stateParams: enteringData.stateParams
+ });
+
// if the current state has cache:false
// or the element has cache-view="false" attribute
if (viewState(viewLocals).cache === false || viewState(viewLocals).cache === 'false' ||
@@ -404,4 +350,69 @@ function($timeout, $document, $q, $ionicClickBlock, $ionicConfig, $ionicNavBarDe
return ionicViewSwitcher;
+
+ function getViewElementIdentifier(locals, view) {
+ if (viewState(locals).abstract) return viewState(locals).name;
+ if (view) return view.stateId || view.viewId;
+ return ionic.Utils.nextUid();
+ }
+
+ function viewState(locals) {
+ return locals && locals.$$state && locals.$$state.self || {};
+ }
+
+ function getTransitionData(viewLocals, enteringEle, direction, view) {
+ // Priority
+ // 1) attribute directive on the button/link to this view
+ // 2) entering element's attribute
+ // 3) entering view's $state config property
+ // 4) view registration data
+ // 5) global config
+ // 6) fallback value
+
+ var state = viewState(viewLocals);
+ var viewTransition = nextTransition || cachedAttr(enteringEle, 'view-transition') || state.viewTransition || $ionicConfig.views.transition() || 'ios';
+ var navBarTransition = $ionicConfig.navBar.transition();
+ direction = nextDirection || cachedAttr(enteringEle, 'view-direction') || state.viewDirection || direction || 'none';
+
+ return extend(getViewData(view), {
+ transition: viewTransition,
+ navBarTransition: navBarTransition === 'view' ? viewTransition : navBarTransition,
+ direction: direction,
+ shouldAnimate: (viewTransition !== 'none' && direction !== 'none')
+ });
+ }
+
+ function getViewData(view) {
+ view = view || {};
+ return {
+ viewId: view.viewId,
+ historyId: view.historyId,
+ stateId: view.stateId,
+ stateName: view.stateName,
+ stateParams: view.stateParams
+ };
+ }
+
+ function navViewAttr(ele, value) {
+ if (arguments.length > 1) {
+ cachedAttr(ele, NAV_VIEW_ATTR, value);
+ } else {
+ return cachedAttr(ele, NAV_VIEW_ATTR);
+ }
+ }
+
+ function destroyViewEle(ele) {
+ // we found an element that should be removed
+ // destroy its scope, then remove the element
+ if (ele && ele.length) {
+ var viewScope = ele.scope();
+ if (viewScope) {
+ viewScope.$emit('$ionicView.unloaded', ele.data(DATA_VIEW));
+ viewScope.$destroy();
+ }
+ ele.remove();
+ }
+ }
+
}]);
diff --git a/scss/_transitions.scss b/scss/_transitions.scss
index 91b1012a9e..dea82a5678 100644
--- a/scss/_transitions.scss
+++ b/scss/_transitions.scss
@@ -68,9 +68,6 @@ $ios-transition-container-bg-color: #000 !default;
}
}
- .back-button {
- @include transition-duration(0);
- }
}
diff --git a/test/unit/angular/directive/navView.unit.js b/test/unit/angular/directive/navView.unit.js
index 1666aa44df..5dab25e0cc 100644
--- a/test/unit/angular/directive/navView.unit.js
+++ b/test/unit/angular/directive/navView.unit.js
@@ -565,6 +565,11 @@ describe('Ionic nav-view', function() {
it('should not cache ion-nav-views that were forward when moving back', inject(function ($state, $q, $timeout, $compile, $ionicConfig) {
elem.append($compile('
')(scope));
+ var unloaded;
+ scope.$on('$ionicView.unloaded', function(ev, d){
+ unloaded = d;
+ });
+
$ionicConfig.views.maxCache(2);
$state.go(page1State);
@@ -581,26 +586,32 @@ describe('Ionic nav-view', function() {
$q.flush();
$timeout.flush();
expect(elem.find('ion-nav-view').find('div').length).toBe(3);
+ expect(unloaded).toBeUndefined();
$state.go(page4State);
$q.flush();
$timeout.flush();
expect(elem.find('ion-nav-view').find('div').length).toBe(3);
+ expect(unloaded.historyId).toBe('root');
+ expect(unloaded.stateName).toBe('page1');
$state.go(page3State);
$q.flush();
$timeout.flush();
expect(elem.find('ion-nav-view').find('div').length).toBe(2);
+ expect(unloaded.stateName).toBe('page4');
$state.go(page2State);
$q.flush();
$timeout.flush();
expect(elem.find('ion-nav-view').find('div').length).toBe(1);
+ expect(unloaded.stateName).toBe('page3');
$state.go(page1State);
$q.flush();
$timeout.flush();
expect(elem.find('ion-nav-view').find('div').length).toBe(1);
+ expect(unloaded.stateName).toBe('page2');
}));
it('should cache ion-nav-views that were forward when moving back with $ionicConfig.cacheForwardViews=true', inject(function ($state, $q, $timeout, $compile, $ionicConfig) {
@@ -870,6 +881,11 @@ describe('Ionic nav-view', function() {
it('should clear ion-nav-view cache', inject(function ($state, $q, $timeout, $compile, $ionicHistory) {
elem.append($compile('
')(scope));
+ var clearCacheCollection = [];
+ scope.$on('$ionicView.unloaded', function(ev, d){
+ clearCacheCollection.push(d);
+ });
+
$state.go(page1State);
$q.flush();
$timeout.flush();
@@ -894,8 +910,14 @@ describe('Ionic nav-view', function() {
expect(divs.eq(2).attr('nav-view')).toBe('active');
expect(divs.eq(2).text()).toBe('page3');
+ expect(clearCacheCollection.length).toBe(0);
$ionicHistory.clearCache();
+ expect(clearCacheCollection.length).toBe(2);
+ expect(clearCacheCollection[0].stateName).toBe('page1');
+ expect(clearCacheCollection[1].stateName).toBe('page2');
+ clearCacheCollection = [];
+
var divs = elem.find('ion-nav-view').find('div');
expect(divs.length).toBe(1);
@@ -903,6 +925,7 @@ describe('Ionic nav-view', function() {
expect(divs.eq(0).text()).toBe('page3');
$ionicHistory.clearCache();
+ expect(clearCacheCollection.length).toBe(0);
var divs = elem.find('ion-nav-view').find('div');
expect(divs.length).toBe(1);
@@ -919,6 +942,7 @@ describe('Ionic nav-view', function() {
expect(divs.eq(0).attr('nav-view')).toBe('active');
expect(divs.eq(0).text()).toBe('page2');
+ expect(clearCacheCollection[0].stateName).toBe('page3');
}));
it('should create and cache tabs', inject(function ($state, $q, $timeout, $compile, $ionicConfig) {