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

feat($animate): add support for customFilter #14914

Closed

Conversation

gkalpak
Copy link
Member

@gkalpak gkalpak commented Jul 15, 2016

What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
Feature.

What is the new behavior (if this is a feature change)?
This commit adds a new customFilter() function on $animateProvider (similar to classNameFilter()), which can be used to filter animations (i.e. decide whether they are allowed or not), based on the return value of a custom filter function.
This allows to easily create arbitrarily complex rules for filtering animations, such as allowing specific events only, or enabling animations on specific subtrees of the DOM etc.

Does this PR introduce a breaking change?
No.

Please check if the PR fulfills these requirements

Other information:
Fixes #14891.

Needs docs:

  • Complete the API docs.
  • Update the Developer Guide.

$animateProvider.customFilter(angular.noop);
expect($animateProvider.customFilter()).toEqual(jasmine.any(Function));

$animateProvider.customFilter({});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps we should throw instead of silently ignoring?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept this consistent with classNameFilter (although it is preferrable to throw obviously).
Throwing would be a BC for classNameFilter. Should I fix this one to throw and make classNameFilter throw for 1.6 (or leave it as is)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would change both as you suggest.

Copy link
Member Author

@gkalpak gkalpak Jan 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed that this needed to land in 1.6.0 (due to the BC) 😞
I will make only customFilter throw for 1.6.x/1.7.x and change classNameFilter to also throw for 1.7.x only.

Copy link
Member Author

@gkalpak gkalpak Jan 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I just realized that the current implementation allows to "clear" the filter/className by passing a non-Function/non-RegExp argument. So, if we want to throw, we need to still allow some special value (e.g. null/undefined/falsy?) for unsetting the filter/className.

@petebacondarwin
Copy link
Contributor

One minor question - otherwise LGTM

@Narretz
Copy link
Contributor

Narretz commented Jul 21, 2016

I like it. I would add a note though that this going to be called for every animatable action, so developers should keep the function lean.

@gkalpak
Copy link
Member Author

gkalpak commented Jan 12, 2017

I added docs for customFilter() (and a large-ish docs commit that face-lifts the Animations Guide - sorry).
I didn't make any change wrt throwing on "invalid" argument types, because of #14914 (comment).

Feel free to TAL ☺️

@@ -233,6 +234,45 @@ var $AnimateProvider = ['$provide', /** @this */ function($provide) {

/**
* @ngdoc method
* @name $animateProvider#customFilter
*
* @description
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add two things:

  • How does this relate to the classFilter, .i.e. what takes precedence, or do both run
  • Note that this runs for every animatable action, not just for animations that are actually defined, and that the user should keep the function fast

You've added this to the guide, but I think it should be here too

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this relate to the classFilter, .i.e. what takes precedence, or do both run

👍

Note that this runs for every animatable action, not just for animations that are actually defined, and that the user should keep the function fast

You mean in addition to the alert-box below?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If possible, I thought we should make it explicit (in the alert box) that this doesn't only affect the actual animations, but every "action" (class change, element entering). I think this difference is easily forgotten, and people might think "Oh well I don't have many animations anyway".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean now. Good point. I will update the API docs and guide.
BTW, I think we should re-order the conditions, because now customFilter and classNameFilter are executed even if animations are globally disabled or the document is hidden etc.

triggered, will attempt to perform a CSS Transition, CSS Keyframe Animation or a JavaScript callback Animation (depending on if an animation is
placed on the given directive). Animations can be placed using vanilla CSS by following the naming conventions set in place by AngularJS
or with JavaScript code when it's defined as a factory.
AngularJS provides animation hooks for common directives such as `ngRepeat`, `ngSwitch`, and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While you are at it, can you add links to the directives here?

This ensures that the whole app has been compiled fully before animations are attempted.
Internally, `ngAnimate` waits until all template downloads that are started right after bootstrap
have finished. Then, it waits for the currently running {@link ng.$rootScope.Scope#$digest $digest}
and the one more after that to finish. This ensures that the whole app has been compiled fully
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"and one more after that, to finish."

With a single `boolean` argument, it enables / disables animations globally: `$animate.enabled(false)`
disables all animations in your app.
With a single `boolean` argument, it enables / disables animations globally:
`$animate.enabled(false)` disables all animations in your app.

When the first argument is a native DOM or jqLite/jQuery element, the function enables / disables
animations on this element *and all its children*: `$animate.enabled(myElement, false)`. This is the
most flexible way to change the animation state. For example, even if you have used it to disable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is "This is the most flexible way to change the animation state." still true with the new customFilter? I don't think so, as $animate.enabled() does not work when the classNameFilter or customFilter are active. So let's remove this sentence



### Enable animations for elements outside of the Angular application DOM tree: {@link ng.$animate#pin $animate.pin()}
### Enable animations outside of the application DOM tree: {@link ng.$animate#pin $animate.pin()}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be ##

@gkalpak
Copy link
Member Author

gkalpak commented Jan 26, 2017

Comments addressed. PTAL

@gkalpak gkalpak force-pushed the feat-animate-support-selectorFilter branch from 3a78cf7 to 8c7a7b8 Compare January 26, 2017 23:14
@@ -233,6 +234,45 @@ var $AnimateProvider = ['$provide', /** @this */ function($provide) {

/**
* @ngdoc method
* @name $animateProvider#customFilter
*
* @description
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If possible, I thought we should make it explicit (in the alert box) that this doesn't only affect the actual animations, but every "action" (class change, element entering). I think this difference is easily forgotten, and people might think "Oh well I don't have many animations anyway".

@gkalpak
Copy link
Member Author

gkalpak commented Jan 31, 2017

Note to self: Update links after #15654.

@Narretz
Copy link
Contributor

Narretz commented Mar 31, 2017

This looks (almost) done, wanna put it into 1.6.5?

@gkalpak gkalpak modified the milestones: 1.6.5, Backlog Mar 31, 2017
@Narretz
Copy link
Contributor

Narretz commented Apr 21, 2017

@gkalpak Looks like this needs a rebase. After that, I will do another review - or do you have some other changes to make?

gkalpak added 2 commits April 27, 2017 13:47
…mprovements)

- List missing animation-aware directives.
- Fix/Improve wording/formatting.
- Fix typos.
- Limit lines to 100 chars.
This commit adds a new `customFilter()` function on `$animateProvider` (similar
to `classNameFilter()`), which can be used to filter animations (i.e. decide
whether they are allowed or not), based on the return value of a custom filter
function.
This allows to easily create arbitrarily complex rules for filtering animations,
such as allowing specific events only, or enabling animations on specific
subtrees of the DOM, etc.

Fixes angular#14891
@gkalpak gkalpak force-pushed the feat-animate-support-selectorFilter branch from 8c7a7b8 to 7e6660c Compare April 27, 2017 11:50
@gkalpak gkalpak force-pushed the feat-animate-support-selectorFilter branch from 7e6660c to 237874b Compare April 27, 2017 12:36
@gkalpak
Copy link
Member Author

gkalpak commented Apr 27, 2017

I have squashed and rebased this and added two new commits:

  • One for further clarifying when the customFilter function is called.
  • One for skipping the customFilter and classNameFilter checks, if animations are globally disabled.

@Narretz PTAL

Copy link
Contributor

@Narretz Narretz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just two smaller docs changes needed, otherwise LGTM

addClass: function(element, className, done) {},
removeClass: function(element, className, done) {}
}
});
```

With these generated CSS class names present on the element at the time, AngularJS automatically
figures out whether to perform a CSS and/or JavaScript animation. If both CSS and JavaScript animation
code is present, and match the CSS class name on the element, then AngularJS will run both animations at the same time.
figures out whether to perform a CSS and/or JavaScript animation. If both CSS and JavaScript
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, what happens if both are detected. Who wins?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JS animations - because you can run CSS in JS: http://plnkr.co/edit/rdRAZTiXHNAFTEOHyZVo?p=preview

Although I'm surprised this isn't explicitly said in the migrate docs. But it is here: https://code.angularjs.org/snapshot/docs/api/ngAnimate

Unfortuante spreading out of content ... moving this in guide would be a good passion project for rainy afternoons. :p

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed and added a link to that api/ngAnimate section.
There is indeed useful info there that would be better in the guide 😞

AngularJS also pays attention to CSS class changes on elements by triggering the **add** and
**remove** hooks. This means that if a CSS class is added to or removed from an element then an
animation can be executed in between, before the CSS class addition or removal is finalized.
(Keep in mind that AngularJS will only be able to capture class changes if an **expression** or the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think interpolated expression is clearer here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@gkalpak gkalpak closed this in 8f563e2 Apr 28, 2017
@gkalpak gkalpak deleted the feat-animate-support-selectorFilter branch April 28, 2017 09:54
gkalpak added a commit that referenced this pull request May 2, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ngAnimate: Set class name filter to include also children elements?
4 participants