From 571323175dcb45caf09ad4acf6d1d9a59f058ce1 Mon Sep 17 00:00:00 2001 From: Martin Staffa Date: Mon, 30 Nov 2015 12:23:05 +0100 Subject: [PATCH] fix(ngAnimate): don't normalize classes on follow-up animations to joined animations This allows follow-up animations to remove a class that is currently being added. Fixes #13380 --- src/ngAnimate/animateQueue.js | 18 ++++++--------- test/ngAnimate/integrationSpec.js | 38 +++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/ngAnimate/animateQueue.js b/src/ngAnimate/animateQueue.js index 04f837c8aaa9..e1b3ef5bde8f 100644 --- a/src/ngAnimate/animateQueue.js +++ b/src/ngAnimate/animateQueue.js @@ -360,19 +360,15 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { // so an example would involve a leave animation taking over an enter. Then when // the postDigest kicks in the enter will be ignored. var joinAnimationFlag = isAllowed('join', element, newAnimation, existingAnimation); - if (joinAnimationFlag) { - if (existingAnimation.state === RUNNING_STATE) { - normalizeAnimationOptions(element, options); - } else { - applyGeneratedPreparationClasses(element, isStructural ? event : null, options); + if (joinAnimationFlag && existingAnimation.state < RUNNING_STATE) { + applyGeneratedPreparationClasses(element, isStructural ? event : null, options); - event = newAnimation.event = existingAnimation.event; - options = mergeAnimationOptions(element, existingAnimation.options, newAnimation.options); + event = newAnimation.event = existingAnimation.event; + options = mergeAnimationOptions(element, existingAnimation.options, newAnimation.options); - //we return the same runner since only the option values of this animation will - //be fed into the `existingAnimation`. - return existingAnimation.runner; - } + //we return the same runner since only the option values of this animation will + //be fed into the `existingAnimation`. + return existingAnimation.runner; } } } else { diff --git a/test/ngAnimate/integrationSpec.js b/test/ngAnimate/integrationSpec.js index 8f6cde838b55..b117301af374 100644 --- a/test/ngAnimate/integrationSpec.js +++ b/test/ngAnimate/integrationSpec.js @@ -351,6 +351,44 @@ describe('ngAnimate integration tests', function() { dealoc(element); })); + + + it("should not normalize classes in a follow-up animation to a joined class-based animation", + inject(function($animate, $animateCss, $rootScope, $document, $rootElement, $$rAF) { + + ss.addRule('.hide', 'opacity: 0'); + ss.addRule('.hide-add, .hide-remove', 'transition: 1s linear all'); + + jqLite($document[0].body).append($rootElement); + element = jqLite('
'); + $rootElement.append(element); + + // These animations will be joined together + $animate.addClass(element, 'red'); + $animate.addClass(element, 'hide'); + $rootScope.$digest(); + + expect(element).toHaveClass('red-add'); + expect(element).toHaveClass('hide-add'); + + // When a digest has passed, but no $rAF has been issued yet, .hide hasn't been added to + // the element, which means class normalization does not allow .hide to get removed + $animate.removeClass(element, 'hide'); + $rootScope.$digest(); + $$rAF.flush(); + + expect(element).toHaveClass('hide-remove hide-remove-active'); + + //End the animation process + browserTrigger(element, 'transitionend', + { timeStamp: Date.now() + 1000, elapsedTime: 2 }); + $animate.flush(); + + expect(element).not.toHaveClass('hide-add-active red-add-active'); + expect(element).toHaveClass('red'); + expect(element).not.toHaveClass('hide'); + })); + }); describe('JS animations', function() {