Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 222d473

Browse files
Isaac Shapirabtford
Isaac Shapira
authored andcommitted
fix(ngAnimate): $animate methods should accept native dom elements
1 parent 24c844d commit 222d473

File tree

2 files changed

+170
-2
lines changed

2 files changed

+170
-2
lines changed

src/ngAnimate/animate.js

+17-1
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,10 @@ angular.module('ngAnimate', ['ng'])
354354
}
355355
}
356356

357+
function prepareElement(element) {
358+
return element && angular.element(element);
359+
}
360+
357361
function stripCommentsFromElement(element) {
358362
return angular.element(extractElementNode(element));
359363
}
@@ -612,6 +616,10 @@ angular.module('ngAnimate', ['ng'])
612616
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
613617
*/
614618
enter : function(element, parentElement, afterElement, doneCallback) {
619+
element = angular.element(element);
620+
parentElement = prepareElement(parentElement);
621+
afterElement = prepareElement(afterElement);
622+
615623
this.enabled(false, element);
616624
$delegate.enter(element, parentElement, afterElement);
617625
$rootScope.$$postDigest(function() {
@@ -651,6 +659,7 @@ angular.module('ngAnimate', ['ng'])
651659
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
652660
*/
653661
leave : function(element, doneCallback) {
662+
element = angular.element(element);
654663
cancelChildAnimations(element);
655664
this.enabled(false, element);
656665
$rootScope.$$postDigest(function() {
@@ -694,6 +703,10 @@ angular.module('ngAnimate', ['ng'])
694703
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
695704
*/
696705
move : function(element, parentElement, afterElement, doneCallback) {
706+
element = angular.element(element);
707+
parentElement = prepareElement(parentElement);
708+
afterElement = prepareElement(afterElement);
709+
697710
cancelChildAnimations(element);
698711
this.enabled(false, element);
699712
$delegate.move(element, parentElement, afterElement);
@@ -733,6 +746,7 @@ angular.module('ngAnimate', ['ng'])
733746
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
734747
*/
735748
addClass : function(element, className, doneCallback) {
749+
element = angular.element(element);
736750
element = stripCommentsFromElement(element);
737751
performAnimation('addClass', className, element, null, null, function() {
738752
$delegate.addClass(element, className);
@@ -769,6 +783,7 @@ angular.module('ngAnimate', ['ng'])
769783
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
770784
*/
771785
removeClass : function(element, className, doneCallback) {
786+
element = angular.element(element);
772787
element = stripCommentsFromElement(element);
773788
performAnimation('removeClass', className, element, null, null, function() {
774789
$delegate.removeClass(element, className);
@@ -803,6 +818,7 @@ angular.module('ngAnimate', ['ng'])
803818
* CSS classes have been set on the element
804819
*/
805820
setClass : function(element, add, remove, doneCallback) {
821+
element = angular.element(element);
806822
element = stripCommentsFromElement(element);
807823
performAnimation('setClass', [add, remove], element, null, null, function() {
808824
$delegate.setClass(element, add, remove);
@@ -815,7 +831,7 @@ angular.module('ngAnimate', ['ng'])
815831
* @function
816832
*
817833
* @param {boolean=} value If provided then set the animation on or off.
818-
* @param {DOMElement=} element If provided then the element will be used to represent the enable/disable operation
834+
* @param {DOMElement} element If provided then the element will be used to represent the enable/disable operation
819835
* @return {boolean} Current animation state.
820836
*
821837
* @description

test/ngAnimate/animateSpec.js

+153-1
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,24 @@ describe("ngAnimate", function() {
297297
expect(element.contents().length).toBe(1);
298298
}));
299299

300+
it("should animate the enter animation event with native dom elements",
301+
inject(function($animate, $rootScope, $sniffer, $timeout) {
302+
element[0].removeChild(child[0]);
303+
304+
expect(element.contents().length).toBe(0);
305+
$animate.enter(child[0], element[0]);
306+
$rootScope.$digest();
307+
308+
if($sniffer.transitions) {
309+
$animate.triggerReflow();
310+
expect(child.hasClass('ng-enter')).toBe(true);
311+
expect(child.hasClass('ng-enter-active')).toBe(true);
312+
browserTrigger(element, 'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1 });
313+
}
314+
315+
expect(element.contents().length).toBe(1);
316+
}));
317+
300318

301319
it("should animate the leave animation event",
302320
inject(function($animate, $rootScope, $sniffer, $timeout) {
@@ -315,6 +333,22 @@ describe("ngAnimate", function() {
315333
expect(element.contents().length).toBe(0);
316334
}));
317335

336+
it("should animate the leave animation event with native dom elements",
337+
inject(function($animate, $rootScope, $sniffer, $timeout) {
338+
339+
expect(element.contents().length).toBe(1);
340+
$animate.leave(child[0]);
341+
$rootScope.$digest();
342+
343+
if($sniffer.transitions) {
344+
$animate.triggerReflow();
345+
expect(child.hasClass('ng-leave')).toBe(true);
346+
expect(child.hasClass('ng-leave-active')).toBe(true);
347+
browserTrigger(child,'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1 });
348+
}
349+
350+
expect(element.contents().length).toBe(0);
351+
}));
318352

319353
it("should animate the move animation event",
320354
inject(function($animate, $compile, $rootScope, $timeout, $sniffer) {
@@ -335,6 +369,24 @@ describe("ngAnimate", function() {
335369
expect(element.text()).toBe('21');
336370
}));
337371

372+
it("should animate the move animation event with native dom elements",
373+
inject(function($animate, $compile, $rootScope, $timeout, $sniffer) {
374+
375+
$rootScope.$digest();
376+
element.empty();
377+
378+
var child1 = $compile('<div>1</div>')($rootScope);
379+
var child2 = $compile('<div>2</div>')($rootScope);
380+
element.append(child1);
381+
element.append(child2);
382+
expect(element.text()).toBe('12');
383+
$animate.move(child1[0], element[0], child2[0]);
384+
$rootScope.$digest();
385+
if($sniffer.transitions) {
386+
$animate.triggerReflow();
387+
}
388+
expect(element.text()).toBe('21');
389+
}));
338390

339391
it("should animate the show animation event",
340392
inject(function($animate, $rootScope, $sniffer, $timeout) {
@@ -354,7 +406,6 @@ describe("ngAnimate", function() {
354406
expect(child).toBeShown();
355407
}));
356408

357-
358409
it("should animate the hide animation event",
359410
inject(function($animate, $rootScope, $sniffer, $timeout) {
360411

@@ -409,6 +460,43 @@ describe("ngAnimate", function() {
409460
});
410461
});
411462

463+
it("should exclusively animate the setClass animation event with native dom elements", function() {
464+
var count = 0, fallback = jasmine.createSpy('callback');
465+
module(function($animateProvider) {
466+
$animateProvider.register('.classify', function() {
467+
return {
468+
beforeAddClass : fallback,
469+
addClass : fallback,
470+
beforeRemoveClass : fallback,
471+
removeClass : fallback,
472+
473+
beforeSetClass : function(element, add, remove, done) {
474+
count++;
475+
expect(add).toBe('yes');
476+
expect(remove).toBe('no');
477+
done();
478+
},
479+
setClass : function(element, add, remove, done) {
480+
count++;
481+
expect(add).toBe('yes');
482+
expect(remove).toBe('no');
483+
done();
484+
}
485+
};
486+
});
487+
});
488+
inject(function($animate, $rootScope, $sniffer, $timeout) {
489+
child.attr('class','classify no');
490+
$animate.setClass(child[0], 'yes', 'no');
491+
$animate.triggerReflow();
492+
493+
expect(child.hasClass('yes')).toBe(true);
494+
expect(child.hasClass('no')).toBe(false);
495+
expect(count).toBe(2);
496+
497+
expect(fallback).not.toHaveBeenCalled();
498+
});
499+
});
412500

413501
it("should delegate down to addClass/removeClass if a setClass animation is not found", function() {
414502
var count = 0;
@@ -2069,6 +2157,39 @@ describe("ngAnimate", function() {
20692157
expect(captured).toBe('addClass-some-class');
20702158
}));
20712159

2160+
it("should perform the animation if passed native dom element",
2161+
inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout, $browser) {
2162+
2163+
var element = jqLite('<div class="klassy"></div>');
2164+
$rootElement.append(element);
2165+
body.append($rootElement);
2166+
2167+
//skipped animations
2168+
captured = 'none';
2169+
$animate.removeClass(element[0], 'some-class');
2170+
expect(element.hasClass('some-class')).toBe(false);
2171+
expect(captured).toBe('none');
2172+
2173+
element.addClass('some-class');
2174+
2175+
captured = 'nothing';
2176+
$animate.addClass(element[0], 'some-class');
2177+
expect(captured).toBe('nothing');
2178+
expect(element.hasClass('some-class')).toBe(true);
2179+
2180+
//actual animations
2181+
captured = 'none';
2182+
$animate.removeClass(element[0], 'some-class');
2183+
$animate.triggerReflow();
2184+
expect(element.hasClass('some-class')).toBe(false);
2185+
expect(captured).toBe('removeClass-some-class');
2186+
2187+
captured = 'nothing';
2188+
$animate.addClass(element[0], 'some-class');
2189+
$animate.triggerReflow();
2190+
expect(element.hasClass('some-class')).toBe(true);
2191+
expect(captured).toBe('addClass-some-class');
2192+
}));
20722193

20732194
it("should add and remove CSS classes after an animation even if no animation is present",
20742195
inject(function($animate, $rootScope, $sniffer, $rootElement) {
@@ -2204,6 +2325,37 @@ describe("ngAnimate", function() {
22042325
expect(signature).toBe('XY');
22052326
}));
22062327

2328+
it("should properly execute JS animations if passed native dom element",
2329+
inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) {
2330+
2331+
var parent = jqLite('<div><span></span></div>');
2332+
$rootElement.append(parent);
2333+
body.append($rootElement);
2334+
var element = jqLite(parent.find('span'));
2335+
2336+
var signature = '';
2337+
2338+
$animate.addClass(element[0],'klassy', function() {
2339+
signature += 'X';
2340+
});
2341+
$animate.triggerReflow();
2342+
2343+
$timeout.flush(500);
2344+
2345+
expect(element.hasClass('klassy')).toBe(true);
2346+
2347+
$animate.removeClass(element[0],'klassy', function() {
2348+
signature += 'Y';
2349+
});
2350+
$animate.triggerReflow();
2351+
2352+
$timeout.flush(3000);
2353+
2354+
expect(element.hasClass('klassy')).toBe(false);
2355+
2356+
$animate.triggerCallbacks();
2357+
expect(signature).toBe('XY');
2358+
}));
22072359

22082360
it("should properly execute CSS animations/transitions and use callbacks when using addClass / removeClass",
22092361
inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) {

0 commit comments

Comments
 (0)