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

Commit 0681a54

Browse files
committed
feat(ngAnimate): ensure JS animations recognize $animateCss directly
JS Animations now recognize the response object returned from a call to `$animateCss`. We can now setup our JS animation code to fully rely on $animateCss to take charge without having to call the doneFn callback on our own. ```js // before .animation('.my-css-animation', function($animateCss) { return { enter: function(element, doneFn) { var animator = $animateCss(element, { event: 'enter', structural: true, from: { background: 'red' }, to: { background: 'blue' } }); animator.start().done(doneFn); } }; }); // now .animation('.my-css-animation', function($animateCss) { return { enter: function(element) { return $animateCss(element, { event: 'enter', structural: true, from: { background: 'red' }, to: { background: 'blue' } }); } }; }); ```
1 parent d5683d2 commit 0681a54

File tree

3 files changed

+82
-18
lines changed

3 files changed

+82
-18
lines changed

src/ngAnimate/animateCss.js

+9-16
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,11 @@
3939
* return {
4040
* enter: function(element, doneFn) {
4141
* var height = element[0].offsetHeight;
42-
* var animator = $animateCss(element, {
42+
* return $animateCss(element, {
4343
* from: { height:'0px' },
4444
* to: { height:height + 'px' },
4545
* duration: 1 // one second
4646
* });
47-
* animator.start().done(doneFn);
4847
* }
4948
* }
5049
* }]);
@@ -67,14 +66,13 @@
6766
* return {
6867
* enter: function(element, doneFn) {
6968
* var height = element[0].offsetHeight;
70-
* var animator = $animateCss(element, {
69+
* return $animateCss(element, {
7170
* addClass: 'red large-text pulse-twice',
7271
* easing: 'ease-out',
7372
* from: { height:'0px' },
7473
* to: { height:height + 'px' },
7574
* duration: 1 // one second
7675
* });
77-
* animator.start().done(doneFn);
7876
* }
7977
* }
8078
* }]);
@@ -171,19 +169,14 @@
171169
* applied to the element during the preparation phase). Note that all other properties such as duration, delay, transitions and keyframes are just properties
172170
* and that changing them will not reconfigure the parameters of the animation.
173171
*
174-
* By calling `animation.start()` we do get back a promise, however, due to the nature of animations we may not want to tap into the default behaviour of
175-
* animations (since they cause a digest to occur which may slow down the animation performance-wise). Therefore instead of calling `then` to capture when
176-
* the animation ends be sure to call `done(callback)` (this is the recommended way to use `$animateCss` within JavaScript-animations).
172+
* ### runner.done() vs runner.then()
173+
* It is documented that `animation.start()` will return a promise object and this is true, however, there is also an additional method available on the
174+
* runner called `.done(callbackFn)`. The done method works the same as `.finally(callbackFn)`, however, it does **not trigger a digest to occur**.
175+
* Therefore, for performance reasons, it's always best to use `runner.done(callback)` instead of `runner.then()`, `runner.catch()` or `runner.finally()`
176+
* unless you really need a digest to kick off afterwards.
177177
*
178-
* The example below should put this into perspective:
179-
*
180-
* ```js
181-
* var animator = $animateCss(element, { ... });
182-
* animator.start().done(function() {
183-
* // yaay the animation is over
184-
* doneCallback();
185-
* });
186-
* ```
178+
* Keep in mind that, to make this easier, ngAnimate has tweaked the JS animations API to recognize when a runner instance is returned from $animateCss
179+
* (so there is no need to call `runner.done(doneFn)` inside of your JavaScript animation code). Check the [animation code above](#usage) to see how this works.
187180
*
188181
* @param {DOMElement} element the element that will be animated
189182
* @param {object} options the animation-related options that will be applied during the animation

src/ngAnimate/animateJs.js

+13-2
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,20 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
145145
args.push(options);
146146

147147
var value = fn.apply(fn, args);
148+
if (value) {
149+
if (isFunction(value.start)) {
150+
value = value.start();
151+
}
152+
153+
if (value instanceof $$AnimateRunner) {
154+
value.done(onDone);
155+
} else if (isFunction(value)) {
156+
// optional onEnd / onCancel callback
157+
return value;
158+
}
159+
}
148160

149-
// optional onEnd / onCancel callback
150-
return isFunction(value) ? value : noop;
161+
return noop;
151162
}
152163

153164
function groupEventedAnimations(element, event, options, animations, fnName) {

test/ngAnimate/animateJsSpec.js

+60
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,66 @@ describe("ngAnimate $$animateJs", function() {
544544
});
545545
});
546546

547+
they("$prop should asynchronously render the $prop animation when a start/end animator object is returned",
548+
allEvents, function(event) {
549+
550+
inject(function($$rAF, $$AnimateRunner) {
551+
var runner;
552+
animations[event] = function(element, a, b, c) {
553+
return {
554+
start: function() {
555+
log.push('start ' + event);
556+
return runner = new $$AnimateRunner();
557+
}
558+
};
559+
};
560+
561+
runAnimation(event, function() {
562+
log.push('complete');
563+
});
564+
565+
if (event === 'leave') {
566+
expect(log).toEqual(['start leave']);
567+
runner.end();
568+
$$rAF.flush();
569+
expect(log).toEqual(['start leave', 'dom leave', 'complete']);
570+
} else {
571+
expect(log).toEqual(['dom ' + event, 'start ' + event]);
572+
runner.end();
573+
$$rAF.flush();
574+
expect(log).toEqual(['dom ' + event, 'start ' + event, 'complete']);
575+
}
576+
});
577+
});
578+
579+
they("$prop should asynchronously render the $prop animation when an instance of $$AnimateRunner is returned",
580+
allEvents, function(event) {
581+
582+
inject(function($$rAF, $$AnimateRunner) {
583+
var runner;
584+
animations[event] = function(element, a, b, c) {
585+
log.push('start ' + event);
586+
return runner = new $$AnimateRunner();
587+
};
588+
589+
runAnimation(event, function() {
590+
log.push('complete');
591+
});
592+
593+
if (event === 'leave') {
594+
expect(log).toEqual(['start leave']);
595+
runner.end();
596+
$$rAF.flush();
597+
expect(log).toEqual(['start leave', 'dom leave', 'complete']);
598+
} else {
599+
expect(log).toEqual(['dom ' + event, 'start ' + event]);
600+
runner.end();
601+
$$rAF.flush();
602+
expect(log).toEqual(['dom ' + event, 'start ' + event, 'complete']);
603+
}
604+
});
605+
});
606+
547607
they("$prop should asynchronously reject the before animation if the callback function is called with false", otherEvents, function(event) {
548608
inject(function($$rAF, $rootScope) {
549609
var beforeMethod = 'before' + event.charAt(0).toUpperCase() + event.substr(1);

0 commit comments

Comments
 (0)