disable nganimate for some elements
Asked Answered
A

9

98

I'm using the ngAnimate module, but all my ng-if, ng-show, etc, are affected by that, I want to leverage ngAnimate for some selected elements. For performance and some bugs in elements that shows and hide very speedy.

thanks.

Apostle answered 21/1, 2014 at 4:52 Comment(3)
Add some example code of the issue.Limy
One of the issues is that ngAnimate forces display:block on all your repeaters: ng-hide-add-active, .ng-hide-remove { display: block!important; }Stella
The better question to ask would be "how can I define my CSS to make ngAnimate work correctly for elements that are hidden without completing a full animation loop". The best answer is from Chris Barr below.Zanze
S
53

Just add this to your CSS. It is best if it is the last rule:

.no-animate {
   -webkit-transition: none !important;
   transition: none !important;
}

then add no-animate to the class of element you want to disable. Example:

<div class="no-animate"></div>
Sparge answered 19/6, 2015 at 20:54 Comment(14)
If you're using sass, you don't need the " -webkit-transition: none !important; "Ekaterinodar
Please note that this answer is wrong because IT DISABLES ALL ANIMATIONS, not just those which are handled by Angular.Merri
Have you tried it? let me see a sample of your code. It works for me and over six people that have approved itSparge
I added a .no-animate, .no-animate-children * rule to cover children, etcBoleslaw
For better approaches take a look at the answers below.Gerhardine
@Gerhardine in what way are they better?Sparge
@DavidAddoteye this solution is not viable if you have an ng-show or ng-if over an element with transition.. I mean.. if I have a loader spinner that shows up only during http request and dissapears when request is resolved, adding this class will result in no animating at all!, michael answer is ok, but too tedious to implement, and you should try to avoid css selectors in controllers. Creating a directive is OK, but looking at Blowsie answer you will find that AngularJS team already have provided a flexible way to take care of this problem ;)Chronologist
@Merri I dont think so. the class will not work if it is not added to the element. so it does not disable all animations. Unless you dont understand how css class work.Sparge
@edrain I practically dont see how disabling animation will have something to do with whether an element shows or not. whether an element shows or not has nothing to do with its transition. Lets say the user want to disable transition for the loader - they simply add the class. If they want the transition they remove the class. Maybe you can create a plunkr to explain your position, thank you.Sparge
@DavidAddoteye the issue is that it removes all animations on the element I apply this class to. I have a background animation that I don't want to disable, but ngAnimate seems to think that it should delay hiding my element due to the background animation. An improvement is suggested by by @ChrisBarr - disable animations only during .ng-leave and .ng-enter.Unhorse
This also disables css animations. $animateProvider.classNameFilter or $animate.enabled, like suggested in the other answers, solves the issue in question without drawbacks.Arethaarethusa
This solution is to a specific element and intended to disable CSS animate for those elements this style is applied to. So, I don't get what you mean. Maybe if you can provide further explanationSparge
My point is not that the solution cannot solve the immediate problem. :) However this solution comes with drawbacks, and does not solve the base issue, which is that ngAnimate adds unwanted behavior. That behavior can be disabled for the offending elements via JS as explained in the other answers.Arethaarethusa
@KimballRobinson be careful with that CSS selector .no-animate, .no-animate-children * using a star selector like that can really drag down performance. Remember CSS selectors work RIGHT to left. So you're essentially saying "select ALL elements, and then traverse up the tree to see if ANY of the ancestors also have the .no-animate class. That's a lot of processing...Eduard
V
108

If you want to enable animations for specific elements (as opposed to disabling them for specific elements) you can use the $animateProvider to configure elements with a particular class name (or regex) to animate.

The code below will enable animations for elements that have the angular-animate class:

var myApp = angular.module("MyApp", ["ngAnimate"]);
myApp.config(function($animateProvider) {
  $animateProvider.classNameFilter(/angular-animate/);
})

Here is example markup that includes the angular-animate class to enable animations:

<div ng-init="items=[1,2,3,4,5,6,7,8,9]">
  <input placeholder="Filter with animations." ng-model="f" /> 
  <div class="my-repeat-animation angular-animate" ng-repeat="item in items | filter:f track by item" >
    {{item}}
  </div>
</div>

Plunker example borrowed and modified from this blog where only the first filter has animations (due to having the angular-animate class).

Please note that I'm using angular-animate as an example and it is completely configurable using the .classNameFilter function.

Vituline answered 2/7, 2014 at 22:31 Comment(4)
This is the most elegant solution since it requires opt-in for animations, and animated elements are clearly differentiated from others by class name.Taffrail
use /^(?:(?!ng-animate-disabled).)*$/ regex to disable annimation with ng-animate-disabled class.Epochal
Great solution! I have a paginated table with 20 rows per page. A third of the time to switch pages was being consumed by the browser processing the animation css classes that weren't even being used.Heavy
Did not work in my case, but using and filtering for the class "animated" instead of the class "angular-animate" worked - maybe because of a newer angular version? Anyway, idea is the same, thank you too :)Liberty
G
84

There are two ways you can disbale animations in AngularJS if you have the module ngAnimate as a dependency on your module:

  1. Disable or enable the animation globally on the $animate service:

    $animate.enabled(false);
    
  2. Disable the animations for a specific element - this must be the element for that angular will add the animationstate css classes (e.g. ng-enter, ...)!

    $animate.enabled(false, theElement);
    

As of Angular 1.4 version you should reverse the arguments:

$animate.enabled(theElement, false);

Documentation for $animate.

Gorey answered 21/1, 2014 at 7:13 Comment(4)
This doesn't work on specific elements as expected. If I turn off the animations globally and then enable it on one particular element, it doesn't work.Ashjian
This answer should be removed or edited to specify which version of Angular it actually works on. For 1.2.10 it most definitely does not work for selectively enabling animate for certain elements, which is the whole point of the question AFAICT.Sejm
Does anyone know if Option 2 is working on the 1.2.25 version ?Lacy
Just looking at the documentation (docs.angularjs.org/api/ng/service/$animate) it seems that the «element» is the first parameter to be passed to the enabled function.Berti
B
55

To disable ng-animate for certain elements, using a CSS class, which follows Angular animate paradigm, you can configure ng-animate to test the class using regex.

Config

    var myApp = angular.module("MyApp", ["ngAnimate"]);
    myApp.config(function($animateProvider) {
        $animateProvider.classNameFilter(/^(?:(?!ng-animate-disabled).)*$/);
    })

Usage

Simply add the ng-animate-disabled class to any elements you want to be ignored by ng-animate.


Credit http://davidchin.me/blog/disable-nganimate-for-selected-elements/

Bugbane answered 1/6, 2015 at 12:56 Comment(3)
I think this is the most correct way to filter ngannimate behaviour!Chronologist
It was worth scrolling for this answer.Pegboard
I can confirm that with the latest version of AngularJS this is definitely the best solution for the problem.Demitria
S
53

Just add this to your CSS. It is best if it is the last rule:

.no-animate {
   -webkit-transition: none !important;
   transition: none !important;
}

then add no-animate to the class of element you want to disable. Example:

<div class="no-animate"></div>
Sparge answered 19/6, 2015 at 20:54 Comment(14)
If you're using sass, you don't need the " -webkit-transition: none !important; "Ekaterinodar
Please note that this answer is wrong because IT DISABLES ALL ANIMATIONS, not just those which are handled by Angular.Merri
Have you tried it? let me see a sample of your code. It works for me and over six people that have approved itSparge
I added a .no-animate, .no-animate-children * rule to cover children, etcBoleslaw
For better approaches take a look at the answers below.Gerhardine
@Gerhardine in what way are they better?Sparge
@DavidAddoteye this solution is not viable if you have an ng-show or ng-if over an element with transition.. I mean.. if I have a loader spinner that shows up only during http request and dissapears when request is resolved, adding this class will result in no animating at all!, michael answer is ok, but too tedious to implement, and you should try to avoid css selectors in controllers. Creating a directive is OK, but looking at Blowsie answer you will find that AngularJS team already have provided a flexible way to take care of this problem ;)Chronologist
@Merri I dont think so. the class will not work if it is not added to the element. so it does not disable all animations. Unless you dont understand how css class work.Sparge
@edrain I practically dont see how disabling animation will have something to do with whether an element shows or not. whether an element shows or not has nothing to do with its transition. Lets say the user want to disable transition for the loader - they simply add the class. If they want the transition they remove the class. Maybe you can create a plunkr to explain your position, thank you.Sparge
@DavidAddoteye the issue is that it removes all animations on the element I apply this class to. I have a background animation that I don't want to disable, but ngAnimate seems to think that it should delay hiding my element due to the background animation. An improvement is suggested by by @ChrisBarr - disable animations only during .ng-leave and .ng-enter.Unhorse
This also disables css animations. $animateProvider.classNameFilter or $animate.enabled, like suggested in the other answers, solves the issue in question without drawbacks.Arethaarethusa
This solution is to a specific element and intended to disable CSS animate for those elements this style is applied to. So, I don't get what you mean. Maybe if you can provide further explanationSparge
My point is not that the solution cannot solve the immediate problem. :) However this solution comes with drawbacks, and does not solve the base issue, which is that ngAnimate adds unwanted behavior. That behavior can be disabled for the offending elements via JS as explained in the other answers.Arethaarethusa
@KimballRobinson be careful with that CSS selector .no-animate, .no-animate-children * using a star selector like that can really drag down performance. Remember CSS selectors work RIGHT to left. So you're essentially saying "select ALL elements, and then traverse up the tree to see if ANY of the ancestors also have the .no-animate class. That's a lot of processing...Eduard
P
44

thanks, i wrote a directive which you can place on the element

CoffeeScript:

myApp.directive "disableAnimate", ($animate) ->
  (scope, element) ->
    $animate.enabled(false, element)

JavaScript:

myApp.directive("disableAnimate", function ($animate) {
    return function (scope, element) {
        $animate.enabled(false, element);
    };
});
Pettifogger answered 13/3, 2014 at 15:32 Comment(3)
This is a pretty nifty approach, it's not always clear how to access the element object, and with some of the other approaches I'm afraid I'd be cluttering up my controllers with Javascript hard-referencing one or several elements defined in a template. This feels like a great separation of concerns, kudos!Roughrider
The parameter order is reversed in $animate.enabled, if anyone is wondering why this disables all ng animation. Works like a charm if you use $animate.enabled(element,false);Nitz
Apologies I see that's only applicable to 1.4.x+, the code above is correct for previous versions.Nitz
F
19

I've found that $animate.enabled(false, $element); will work for elements that use ng-show or ng-hide but it will not work for elements that use ng-if for some reason! The solution I ended up using was to just do it all in CSS, which I learned from this thread on GitHub.

CSS

/* Use this for transitions */
.disable-animations.ng-enter,
.disable-animations.ng-leave,
.disable-animations.ng-animate {
  -webkit-transition: none !important;
  transition: none !important;
}

/* Use this for keyframe animations */
.disable-animations.ng-animate {
  -webkit-animation: none 0s;
  animation: none 0s;
}

SCSS

.disable-animations {
  // Use this for transitions
  &.ng-enter,
  &.ng-leave,
  &.ng-animate {
    -webkit-transition: none !important;
    transition: none !important;
  }
  // Use this for keyframe animations
  &.ng-animate {
    -webkit-animation: none 0s;
    animation: none 0s;
  }
}
Franco answered 9/1, 2015 at 14:25 Comment(3)
My case was that with ngAnimate loaded, a class like .loading.ng-hide would stay on screen until a full animation loop completed. This is the cleanest answer, because it is basically just feeding the right configuration to ngAnimate and using it normally. This is preferable to misconfiguring it, then disabling it. So +1 for you, wish I could give more to even out the score here.Zanze
This is the trickiest answer. Doing it with css is more better than messing with js.London
Please look at @Bugbane answer, that is the more generic and correct way to deal with thisChronologist
U
3

I do NOT want to use ngAnimate on my ng-if's, so this would be my solution:

[ng-if] {
  .ng-enter, .ng-leave, .ng-animate {
    -webkit-transition: none !important;
    transition: none !important;
  }
}

Just posting this as another suggestion!

Uvular answered 13/11, 2015 at 9:54 Comment(0)
P
2

I have a list from which the first li is hidden using ng-hide="$first". Using ng-enter results in the li being shown for half a second before disappearing.

Based on Chris Barr's solution, my code now looks like this:

HTML

<ol>
    <li ng-repeat="item in items"
        ng-hide="$first"
        ng-class="{'no-animate' : $first}">
    </li>
</ol>

CSS

.no-animate.ng-enter,
.no-animate.ng-leave,
.no-animate.ng-animate {
        transition: none !important; /* disable transitions */
        animation: none 0s !important; /* disable keyframe animations */
}

li.ng-enter {
    opacity: 0;
    transition: opacity 0.3s ease-out;
}
li.ng-enter-active {
    opacity: 1;
}

/* I use Autoprefixer. If you don't, please include vendor prefixes. */
Parlour answered 21/7, 2015 at 10:42 Comment(0)
T
-1

I know that it is a delayed reply, but here we use in MainController:

// disable all animations
$animate.enabled(false);

But the problem is that when we disable all animations, the ui-select are configured to opacity: 0.

So, its necessary to set opacity to 1 using CSS:

.ui-select-choices {
    opacity: 1 !important;
}

This will properly set opacity and the ui-select will work.

Thomasthomasa answered 5/12, 2017 at 18:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.