From 81d00eac0e15c87a895e8a8341770a712f58aa33 Mon Sep 17 00:00:00 2001 From: Chris Thielen Date: Mon, 29 Feb 2016 20:29:58 -0600 Subject: [PATCH 1/3] Revert "cherry-pick 2523bbd from 0.2.17" This reverts commit e7a3481f8dde021cbdf35fa533b2b4431d23dacb. --- src/ng1/viewDirective.ts | 19 +-------- test/viewDirectiveSpec.js | 81 +++++++++++++-------------------------- 2 files changed, 29 insertions(+), 71 deletions(-) diff --git a/src/ng1/viewDirective.ts b/src/ng1/viewDirective.ts index 47bff217f..389ce90da 100644 --- a/src/ng1/viewDirective.ts +++ b/src/ng1/viewDirective.ts @@ -1,5 +1,3 @@ -var ngMajorVer = angular.version.major; -var ngMinorVer = angular.version.minor; /** @module view */ /** for typedoc */ import {extend} from "../common/common"; import {isDefined} from "../common/predicates"; @@ -31,9 +29,6 @@ import {UIViewData} from "../view/interface"; * service, {@link ui.router.state.$uiViewScroll}. This custom service let's you * scroll ui-view elements into view when they are populated during a state activation. * - * @param {string=} noanimation If truthy, the non-animated renderer will be selected (no animations - * will be applied to the ui-view) - * * *Note: To revert back to old [`$anchorScroll`](http://docs.angularjs.org/api/ng.$anchorScroll) * functionality, call `$uiViewScrollProvider.useAnchorScroll()`.* * @@ -127,26 +122,16 @@ $ViewDirective.$inject = ['$view', '$animate', '$uiViewScroll', '$interpolate', function $ViewDirective( $view, $animate, $uiViewScroll, $interpolate, $q) { function getRenderer(attrs, scope) { - - function animEnabled(element) { - if (!!attrs.noanimation) return false; - return (ngMajorVer === 1 && ngMinorVer >= 4) ? !!$animate.enabled(element) : !!$animate.enabled(); - } - return { enter: function(element, target, cb) { - if (!animEnabled(element)) { - target.after(element); cb(); - } else if (angular.version.minor > 2) { + if (angular.version.minor > 2) { $animate.enter(element, null, target).then(cb); } else { $animate.enter(element, null, target, cb); } }, leave: function(element, cb) { - if (!animEnabled(element)) { - element.remove(); cb(); - } else if (angular.version.minor > 2) { + if (angular.version.minor > 2) { $animate.leave(element).then(cb); } else { $animate.leave(element, cb); diff --git a/test/viewDirectiveSpec.js b/test/viewDirectiveSpec.js index a31dfecc4..48eeedf1a 100644 --- a/test/viewDirectiveSpec.js +++ b/test/viewDirectiveSpec.js @@ -17,7 +17,7 @@ describe('uiView', function () { var log, scope, $compile, elem; beforeEach(function() { - var depends = ['ui.router', 'ui.router.state.events']; + var depends = ['ui.router']; try { angular.module('ngAnimate'); @@ -31,8 +31,7 @@ describe('uiView', function () { module('ui.router.test'); }); - beforeEach(module(function ($provide, $stateEventsProvider) { - $stateEventsProvider.enable(); + beforeEach(module(function ($provide) { $provide.decorator('$uiViewScroll', function () { return jasmine.createSpy('$uiViewScroll'); }); @@ -138,13 +137,17 @@ describe('uiView', function () { .state('m', { template: 'mState', controller: function($scope) { - log += 'ctrl(m);'; - $scope.$on('$destroy', function() { log += '$destroy(m);'; }); - } + log += 'm;'; + $scope.$on('$destroy', function() { + log += '$destroy(m);'; + }); + }, }) .state('n', { template: 'nState', - controller: function($scope) { log += 'ctrl(n);'; } + controller: function($scope) { + log += 'n;'; + }, }) .state('o', oState) })); @@ -157,6 +160,23 @@ describe('uiView', function () { describe('linking ui-directive', function () { + it('$destroy event is triggered after animation ends', inject(function($state, $q, $animate) { + elem.append($compile('
')(scope)); + + $state.transitionTo('m'); + $q.flush(); + expect(log).toBe('m;'); + $state.transitionTo('n'); + $q.flush(); + if ($animate) { + expect(log).toBe('m;n;'); + animateFlush($animate); + expect(log).toBe('m;n;$destroy(m);'); + } else { + expect(log).toBe('m;$destroy(m);n;'); + } + })); + it('anonymous ui-view should be replaced with the template of the current $state', inject(function ($state, $q) { elem.append($compile('
')(scope)); @@ -595,53 +615,6 @@ describe('uiView', function () { // No more animations expect($animate.queue.length).toBe(0); })); - - it ('should disable animations if noanimation="true" is present', inject(function($state, $q, $compile, $animate) { - var content = 'Initial Content', animation; - elem.append($compile('
' + content + '
')(scope)); - - animation = $animate.queue.shift(); - expect(animation).toBeUndefined(); - - $state.transitionTo(aState); - $q.flush(); - animation = $animate.queue.shift(); - expect(animation).toBeUndefined(); - expect(elem.text()).toBe(aState.template); - - $state.transitionTo(bState); - $q.flush(); - animation = $animate.queue.shift(); - expect(animation).toBeUndefined(); - expect(elem.text()).toBe(bState.template); - })); - - describe('$destroy event', function() { - it('is triggered after animation ends', inject(function($state, $q, $animate, $rootScope) { - elem.append($compile('
')(scope)); - - $state.transitionTo('m'); - $q.flush(); - expect(log).toBe('ctrl(m);'); - $state.transitionTo('n'); - $q.flush(); - - expect(log).toBe('ctrl(m);ctrl(n);'); - animateFlush($animate); - expect(log).toBe('ctrl(m);ctrl(n);$destroy(m);'); - })); - - it('is triggered before $stateChangeSuccess if noanimation is present', inject(function($state, $q, $animate, $rootScope) { - elem.append($compile('
')(scope)); - - $state.transitionTo('m'); - $q.flush(); - expect(log).toBe('ctrl(m);'); - $state.transitionTo('n'); - $q.flush(); - expect(log).toBe('ctrl(m);$destroy(m);ctrl(n);'); - })); - }); }); }); From ba2ba8222526172b72dc1a699783b7503cd07d7b Mon Sep 17 00:00:00 2001 From: Chris Thielen Date: Mon, 29 Feb 2016 20:32:14 -0600 Subject: [PATCH 2/3] Revert "cherry-pick 1be1379 from 0.2.17" This reverts commit 94fa6db7488f7f31ed47915eea48cfecd77319ba. --- src/ng1/viewDirective.ts | 35 ++++++++------------------- test/viewDirectiveSpec.js | 51 ++++++--------------------------------- 2 files changed, 17 insertions(+), 69 deletions(-) diff --git a/src/ng1/viewDirective.ts b/src/ng1/viewDirective.ts index 389ce90da..c50e70bfe 100644 --- a/src/ng1/viewDirective.ts +++ b/src/ng1/viewDirective.ts @@ -177,7 +177,7 @@ function $ViewDirective( $view, $animate, $uiViewScroll, $interpolate, trace.traceUiViewEvent("Linking", viewData); function configUpdatedCallback(config?: ViewConfig) { - if (configsEqual(viewConfig, config) || scope._willBeDestroyed) return; + if (configsEqual(viewConfig, config)) return; trace.traceUiViewConfigUpdated(viewData, config && config.context); viewConfig = config; @@ -195,42 +195,27 @@ function $ViewDirective( $view, $animate, $uiViewScroll, $interpolate, }); function cleanupLastView() { - var _previousEl = previousEl; - var _currentScope = currentScope; - - if (_currentScope) { - _currentScope._willBeDestroyed = true; + if (previousEl) { + trace.traceUiViewEvent("Removing (previous) el", viewData); + previousEl.remove(); + previousEl = null; } - function cleanOld() { - if (_previousEl) { - trace.traceUiViewEvent("Removing (previous) el", viewData); - _previousEl.remove(); - _previousEl = null; - } - - if (_currentScope) { - trace.traceUiViewEvent("Destroying (previous) scope", viewData); - _currentScope.$destroy(); - _currentScope = null; - } + if (currentScope) { + trace.traceUiViewEvent("Destroying (previous) scope", viewData); + currentScope.$destroy(); + currentScope = null; } if (currentEl) { trace.traceUiViewEvent("Animate out (previous)", viewData); renderer.leave(currentEl, function() { - cleanOld(); previousEl = null; }); previousEl = currentEl; - } else { - cleanOld(); - previousEl = null; + currentEl = null; } - - currentEl = null; - currentScope = null; } function updateView(config?: ViewConfig) { diff --git a/test/viewDirectiveSpec.js b/test/viewDirectiveSpec.js index 48eeedf1a..b55a9b0f9 100644 --- a/test/viewDirectiveSpec.js +++ b/test/viewDirectiveSpec.js @@ -14,7 +14,7 @@ function animateFlush($animate) { describe('uiView', function () { 'use strict'; - var log, scope, $compile, elem; + var scope, $compile, elem; beforeEach(function() { var depends = ['ui.router']; @@ -37,10 +37,6 @@ describe('uiView', function () { }); })); - beforeEach(function() { - log = ''; - }); - var aState = { template: 'aState template' }, @@ -112,9 +108,8 @@ describe('uiView', function () { } } }, - - oState = { - template: 'oState', + mState = { + template: 'mState', controller: function ($scope, $element) { $scope.elementId = $element.attr('id'); } @@ -134,22 +129,7 @@ describe('uiView', function () { .state('j', jState) .state('k', kState) .state('l', lState) - .state('m', { - template: 'mState', - controller: function($scope) { - log += 'm;'; - $scope.$on('$destroy', function() { - log += '$destroy(m);'; - }); - }, - }) - .state('n', { - template: 'nState', - controller: function($scope) { - log += 'n;'; - }, - }) - .state('o', oState) + .state('m', mState) })); beforeEach(inject(function ($rootScope, _$compile_) { @@ -160,23 +140,6 @@ describe('uiView', function () { describe('linking ui-directive', function () { - it('$destroy event is triggered after animation ends', inject(function($state, $q, $animate) { - elem.append($compile('
')(scope)); - - $state.transitionTo('m'); - $q.flush(); - expect(log).toBe('m;'); - $state.transitionTo('n'); - $q.flush(); - if ($animate) { - expect(log).toBe('m;n;'); - animateFlush($animate); - expect(log).toBe('m;n;$destroy(m);'); - } else { - expect(log).toBe('m;$destroy(m);n;'); - } - })); - it('anonymous ui-view should be replaced with the template of the current $state', inject(function ($state, $q) { elem.append($compile('
')(scope)); @@ -362,11 +325,11 @@ describe('uiView', function () { })); it('should instantiate a controller with both $scope and $element injections', inject(function ($state, $q) { - elem.append($compile('
{{elementId}}
')(scope)); - $state.transitionTo(oState); + elem.append($compile('
{{elementId}}
')(scope)); + $state.transitionTo(mState); $q.flush(); - expect(elem.text()).toBe('oState'); + expect(elem.text()).toBe('mState'); })); describe('play nicely with other directives', function() { From a5578de7e80aac62b21967d4e949ec72c34823fc Mon Sep 17 00:00:00 2001 From: Chris Thielen Date: Tue, 1 Mar 2016 08:21:26 -0600 Subject: [PATCH 3/3] feat(uiView): Put $animate promises on element.data('$uiView') closes #2562 closes #2579 --- src/ng1/viewDirective.ts | 19 +++++++++++----- test/viewDirectiveSpec.js | 46 ++++++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/ng1/viewDirective.ts b/src/ng1/viewDirective.ts index c50e70bfe..4c785488c 100644 --- a/src/ng1/viewDirective.ts +++ b/src/ng1/viewDirective.ts @@ -196,20 +196,22 @@ function $ViewDirective( $view, $animate, $uiViewScroll, $interpolate, function cleanupLastView() { if (previousEl) { - trace.traceUiViewEvent("Removing (previous) el", viewData); + trace.traceUiViewEvent("Removing (previous) el", previousEl.data('$uiView')); previousEl.remove(); previousEl = null; } if (currentScope) { - trace.traceUiViewEvent("Destroying (previous) scope", viewData); + trace.traceUiViewEvent("Destroying scope", viewData); currentScope.$destroy(); currentScope = null; } if (currentEl) { - trace.traceUiViewEvent("Animate out (previous)", viewData); + let _viewData = currentEl.data('$uiView'); + trace.traceUiViewEvent("Animate out", _viewData); renderer.leave(currentEl, function() { + _viewData.$$animLeave.resolve(); previousEl = null; }); @@ -222,17 +224,22 @@ function $ViewDirective( $view, $animate, $uiViewScroll, $interpolate, config = config || {}; let newScope = scope.$new(); trace.traceUiViewScopeCreated(viewData, newScope); + let animEnter = $q.defer(), animLeave = $q.defer(); - extend(viewData, { + let $uiViewData = extend({}, viewData, { context: config.context, $template: config.template, $controller: config.controller, $controllerAs: config.controllerAs, - $locals: config.locals + $locals: config.locals, + $animEnter: animEnter.promise, + $animLeave: animLeave.promise, + $$animLeave: animLeave }); let cloned = $transclude(newScope, function(clone) { - renderer.enter(clone.data('$uiView', viewData), $element, function onUiViewEnter() { + renderer.enter(clone.data('$uiView', $uiViewData), $element, function onUiViewEnter() { + animEnter.resolve(); if (currentScope) { currentScope.$emit('$viewContentAnimationEnded'); } diff --git a/test/viewDirectiveSpec.js b/test/viewDirectiveSpec.js index b55a9b0f9..4ea19818e 100644 --- a/test/viewDirectiveSpec.js +++ b/test/viewDirectiveSpec.js @@ -6,18 +6,14 @@ function animateFlush($animate) { $animate && $animate.flush && $animate.flush(); // 1.4 } -function animateFlush($animate) { - $animate && $animate.triggerCallbacks && $animate.triggerCallbacks(); // 1.2-1.3 - $animate && $animate.flush && $animate.flush(); // 1.4 -} - describe('uiView', function () { 'use strict'; - var scope, $compile, elem; + var scope, $compile, elem, log; beforeEach(function() { var depends = ['ui.router']; + log = ""; try { angular.module('ngAnimate'); @@ -113,6 +109,15 @@ describe('uiView', function () { controller: function ($scope, $element) { $scope.elementId = $element.attr('id'); } + }, + nState = { + template: 'nState', + controller: function ($scope, $element) { + var data = $element.data('$uiView'); + $scope.$on("$destroy", function() { log += 'destroy;'}); + data.$animEnter.then(function() { log += "animEnter;"}); + data.$animLeave.then(function() { log += "animLeave;"}); + } }; beforeEach(module(function ($stateProvider) { @@ -130,6 +135,7 @@ describe('uiView', function () { .state('k', kState) .state('l', lState) .state('m', mState) + .state('n', nState) })); beforeEach(inject(function ($rootScope, _$compile_) { @@ -578,6 +584,34 @@ describe('uiView', function () { // No more animations expect($animate.queue.length).toBe(0); })); + + it ('should expose animation promises to controllers', inject(function($state, $q, $compile, $animate, $transitions) { + $transitions.onStart({}, function($transition$) { log += 'start:' + $transition$.to().name + ';'; }); + $transitions.onFinish({}, function($transition$) { log += 'finish:' + $transition$.to().name + ';'; }); + $transitions.onSuccess({}, function($transition$) { log += 'success:' + $transition$.to().name + ';'; }); + + var content = 'Initial Content'; + elem.append($compile('
' + content + '
')(scope)); + $state.transitionTo('n'); + $q.flush(); + + expect($state.current.name).toBe('n'); + expect(log).toBe('start:n;finish:n;success:n;'); + + animateFlush($animate); + $q.flush(); + expect(log).toBe('start:n;finish:n;success:n;animEnter;'); + + $state.transitionTo('a'); + $q.flush(); + expect($state.current.name).toBe('a'); + expect(log).toBe('start:n;finish:n;success:n;animEnter;start:a;finish:a;destroy;success:a;'); + + animateFlush($animate); + $q.flush(); + expect(log).toBe('start:n;finish:n;success:n;animEnter;start:a;finish:a;destroy;success:a;animLeave;'); + })); + }); });