From aa2133ad818d2e5c27cbd3933061797096356c8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Niemela=CC=88?= Date: Sat, 6 Jul 2013 00:48:54 -0400 Subject: [PATCH] fix(ngInclude): $animate refactoring + use transclusion BREAKING CHANGE: previously ngInclude only updated its content, after this change ngInclude will recreate itself every time a new content is included. This ensures that a single rootElement for all the included contents always exists, which makes definition of css styles for animations much easier. --- docs/src/templates/css/animations.css | 4 +- src/ng/directive/ngInclude.js | 82 ++++++++++++++------------- src/ngAnimate/animate.js | 8 +-- test/ng/directive/ngIncludeSpec.js | 81 +++++++++++++++++--------- 4 files changed, 105 insertions(+), 70 deletions(-) diff --git a/docs/src/templates/css/animations.css b/docs/src/templates/css/animations.css index 7324a8a14330..cc531ccbedaa 100644 --- a/docs/src/templates/css/animations.css +++ b/docs/src/templates/css/animations.css @@ -15,7 +15,7 @@ overflow:hidden; } -.slide-reveal > .ng-enter { +.slide-reveal.ng-enter { -webkit-transition:0.5s linear all; -moz-transition:0.5s linear all; -o-transition:0.5s linear all; @@ -26,7 +26,7 @@ opacity:0; top:10px; } -.slide-reveal > .ng-enter.ng-enter-active { +.slide-reveal.ng-enter.ng-enter-active { top:0; opacity:1; } diff --git a/src/ng/directive/ngInclude.js b/src/ng/directive/ngInclude.js index d5ed1fc52e75..2ab9f847cafc 100644 --- a/src/ng/directive/ngInclude.js +++ b/src/ng/directive/ngInclude.js @@ -24,8 +24,10 @@ * access on some browsers) * * @animations - * enter - happens just after the ngInclude contents change and a new DOM element is created and injected into the ngInclude container - * leave - happens just after the ngInclude contents change and just before the former contents are removed from the DOM + * enter - animation is used to bring new content into the browser. + * leave - animation is used to animate existing content away. + * + * The enter and leave animation occur concurrently. * * @scope * @@ -49,9 +51,9 @@ url of the template: {{template.url}}
-
+
+
+
@@ -63,14 +65,13 @@ } -
Content of template1.html
+ Content of template1.html
-
Content of template2.html
+ Content of template2.html
- .example-leave, - .example-enter { + .include-example.ng-enter, .include-example.ng-leave { -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; -ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; @@ -82,24 +83,21 @@ left:0; right:0; bottom:0; - } - - .example-animate-container > * { display:block; padding:10px; } - .example-enter { + .include-example.ng-enter { top:-50px; } - .example-enter.example-enter-active { + .include-example.ng-enter.ng-enter-active { top:0; } - .example-leave { + .include-example.ng-leave { top:0; } - .example-leave.example-leave-active { + .include-example.ng-leave.ng-leave-active { top:50px; } @@ -115,7 +113,7 @@ }); it('should change to blank', function() { select('template').option(''); - expect(element('.doc-example-live [ng-include]').text()).toEqual(''); + expect(element('.doc-example-live [ng-include]')).toBe(undefined); }); @@ -145,21 +143,26 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile' return { restrict: 'ECA', terminal: true, - compile: function(element, attr) { + transclude: 'element', + compile: function(element, attr, transclusion) { var srcExp = attr.ngInclude || attr.src, onloadExp = attr.onload || '', autoScrollExp = attr.autoscroll; - return function(scope, element, attr) { + return function(scope, $element) { var changeCounter = 0, - childScope; + currentScope, + currentElement; - var clearContent = function() { - if (childScope) { - childScope.$destroy(); - childScope = null; + var cleanupLastIncludeContent = function() { + if (currentScope) { + currentScope.$destroy(); + currentScope = null; + } + if(currentElement) { + $animate.leave(currentElement); + currentElement = null; } - $animate.leave(element.contents()); }; scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) { @@ -168,28 +171,31 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile' if (src) { $http.get(src, {cache: $templateCache}).success(function(response) { if (thisChangeId !== changeCounter) return; + var newScope = scope.$new(); - if (childScope) childScope.$destroy(); - childScope = scope.$new(); - $animate.leave(element.contents()); + transclusion(newScope, function(clone) { + cleanupLastIncludeContent(); - var contents = jqLite('
').html(response).contents(); + currentScope = newScope; + currentElement = clone; - $animate.enter(contents, element); - $compile(contents)(childScope); + currentElement.html(response); + $animate.enter(currentElement, null, $element); + $compile(currentElement.contents())(currentScope); - if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) { - $anchorScroll(); - } + if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) { + $anchorScroll(); + } - childScope.$emit('$includeContentLoaded'); - scope.$eval(onloadExp); + currentScope.$emit('$includeContentLoaded'); + scope.$eval(onloadExp); + }); }).error(function() { - if (thisChangeId === changeCounter) clearContent(); + if (thisChangeId === changeCounter) cleanupLastIncludeContent(); }); scope.$emit('$includeContentRequested'); } else { - clearContent(); + cleanupLastIncludeContent(); } }); }; diff --git a/src/ngAnimate/animate.js b/src/ngAnimate/animate.js index 93ff9d8c8426..201d4aabb08a 100644 --- a/src/ngAnimate/animate.js +++ b/src/ngAnimate/animate.js @@ -47,10 +47,10 @@ * transition:0.5s linear all; * } * - * .slide > .ng-enter { } /* starting animations for enter */ - * .slide > .ng-enter-active { } /* terminal animations for enter */ - * .slide > .ng-leave { } /* starting animations for leave */ - * .slide > .ng-leave-active { } /* terminal animations for leave */ + * .slide.ng-enter { } /* starting animations for enter */ + * .slide.ng-enter-active { } /* terminal animations for enter */ + * .slide.ng-leave { } /* starting animations for leave */ + * .slide.ng-leave-active { } /* terminal animations for leave */ * * *