diff --git a/src/viewDirective.js b/src/viewDirective.js index 6661c078c..c2eaa3d56 100644 --- a/src/viewDirective.js +++ b/src/viewDirective.js @@ -1,3 +1,5 @@ +var ngMajorVer = angular.version.major; +var ngMinorVer = angular.version.minor; /** * @ngdoc directive * @name ui.router.state.directive:ui-view @@ -22,6 +24,9 @@ * 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()`.* * @@ -133,24 +138,35 @@ function $ViewDirective( $state, $injector, $uiViewScroll, $interpolate) // Returns a set of DOM manipulation functions based on which Angular version // it should use function getRenderer(attrs, scope) { - var statics = function() { - return { - enter: function (element, target, cb) { target.after(element); cb(); }, - leave: function (element, cb) { element.remove(); cb(); } - }; + var statics = { + enter: function (element, target, cb) { target.after(element); cb(); }, + leave: function (element, cb) { element.remove(); cb(); } }; + if (!!attrs.noanimation) return statics; + + function animEnabled(element) { + if (ngMajorVer === 1 && ngMinorVer >= 4) return !!$animate.enabled(element); + if (ngMajorVer === 1 && ngMinorVer >= 2) return !!$animate.enabled(); + return (!!$animator); + } + + // ng 1.2+ if ($animate) { return { enter: function(element, target, cb) { - if (angular.version.minor > 2) { + if (!animEnabled(element)) { + statics.enter(element, target, cb); + } else if (angular.version.minor > 2) { $animate.enter(element, null, target).then(cb); } else { $animate.enter(element, null, target, cb); } }, leave: function(element, cb) { - if (angular.version.minor > 2) { + if (!animEnabled(element)) { + statics.leave(element, cb); + } else if (angular.version.minor > 2) { $animate.leave(element).then(cb); } else { $animate.leave(element, cb); @@ -159,6 +175,7 @@ function $ViewDirective( $state, $injector, $uiViewScroll, $interpolate) }; } + // ng 1.1.5 if ($animator) { var animate = $animator && $animator(scope, attrs); @@ -168,7 +185,7 @@ function $ViewDirective( $state, $injector, $uiViewScroll, $interpolate) }; } - return statics(); + return statics; } var directive = { diff --git a/test/viewDirectiveSpec.js b/test/viewDirectiveSpec.js index 0461d7391..fd9566326 100644 --- a/test/viewDirectiveSpec.js +++ b/test/viewDirectiveSpec.js @@ -123,16 +123,12 @@ describe('uiView', function () { .state('l', lState) .state('m', { controller: function($scope) { - log += 'm;'; - $scope.$on('$destroy', function() { - log += '$destroy(m);'; - }); - }, + log += 'ctrl(m);'; + $scope.$on('$destroy', function() { log += '$destroy(m);'; }); + } }) .state('n', { - controller: function($scope) { - log += 'n;'; - }, + controller: function($scope) { log += 'ctrl(n);'; } }); })); @@ -144,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)); @@ -594,5 +573,56 @@ 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); + })); + + it('$destroy event is triggered after animation ends', inject(function($state, $q, $animate, $rootScope) { + elem.append($compile('
')(scope)); + $rootScope.$on('$stateChangeSuccess', function(evt, toState) { log += 'success(' + toState.name + ');'; }); + + $state.transitionTo('m'); + $q.flush(); + expect(log).toBe('success(m);ctrl(m);'); + $state.transitionTo('n'); + $q.flush(); + if ($animate) { + expect(log).toBe('success(m);ctrl(m);success(n);ctrl(n);'); + animateFlush($animate); + expect(log).toBe('success(m);ctrl(m);success(n);ctrl(n);$destroy(m);'); + } else { + expect(log).toBe('success(m);ctrl(m);$destroy(m);success(n);ctrl(n);'); + } + })); + + it('$destroy event is triggered before $stateChangeSuccess if noanimation is present', inject(function($state, $q, $animate, $rootScope) { + elem.append($compile('
')(scope)); + $rootScope.$on('$stateChangeSuccess', function(evt, toState) { log += 'success(' + toState.name + ');'; }); + + $state.transitionTo('m'); + $q.flush(); + expect(log).toBe('success(m);ctrl(m);'); + $state.transitionTo('n'); + $q.flush(); + expect(log).toBe('success(m);ctrl(m);success(n);$destroy(m);ctrl(n);'); + })); + }); });