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.

scniro
  • 16,844
  • 8
  • 62
  • 106
drtobal
  • 1,005
  • 1
  • 7
  • 7
  • 1
    Add some example code of the issue. – cheekybastard Jan 21 '14 at 05:16
  • One of the issues is that ngAnimate forces `display:block` on all your repeaters: ```ng-hide-add-active, .ng-hide-remove { display: block!important; }``` – Somatik Mar 06 '15 at 13:48
  • 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. – Eric Rini Mar 10 '15 at 13:37

9 Answers9

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.

Gloopy
  • 37,767
  • 15
  • 103
  • 71
  • This is the most elegant solution since it requires opt-in for animations, and animated elements are clearly differentiated from others by class name. – Nikola M. Oct 17 '14 at 21:50
  • 9
    use `/^(?:(?!ng-animate-disabled).)*$/` regex to disable annimation with `ng-animate-disabled` class. – IcanDivideBy0 Jan 14 '15 at 11:09
  • 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. – Kevin Aug 26 '15 at 18:25
  • 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 :) – LFish Oct 05 '16 at 15:47
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.

Alejandro García Iglesias
  • 16,222
  • 11
  • 51
  • 64
michael
  • 16,221
  • 7
  • 55
  • 60
  • 2
    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. – Kushagra Gour Aug 06 '14 at 07:41
  • 1
    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. – Trindaz Sep 09 '14 at 13:41
  • Does anyone know if Option 2 is working on the 1.2.25 version ? – khorvat Sep 19 '14 at 14:44
  • 1
    Just looking at the documentation (https://docs.angularjs.org/api/ng/service/$animate) it seems that the «element» is the first parameter to be passed to the enabled function. – DanielM May 27 '15 at 08:48
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/

Blowsie
  • 40,239
  • 15
  • 88
  • 108
52

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>
Mattygabe
  • 1,772
  • 4
  • 23
  • 44
David Addoteye
  • 1,587
  • 1
  • 19
  • 31
  • 2
    If you're using sass, you don't need the " -webkit-transition: none !important; " – Marwen Trabelsi Aug 21 '15 at 09:36
  • 17
    Please note that this answer is wrong because IT DISABLES ALL ANIMATIONS, not just those which are handled by Angular. – stackular Aug 24 '15 at 13:57
  • 1
    Have you tried it? let me see a sample of your code. It works for me and over six people that have approved it – David Addoteye Aug 24 '15 at 14:54
  • 2
    I added a `.no-animate, .no-animate-children *` rule to cover children, etc – Kimball Robinson Jan 06 '16 at 20:35
  • For better approaches take a look at the answers below. – kriskodzi Feb 11 '16 at 11:24
  • @kriskodzi in what way are they better? – David Addoteye Feb 13 '16 at 22:41
  • 1
    @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 ;) – edrian Feb 17 '16 at 17:55
  • @stackular 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. – David Addoteye Feb 20 '16 at 16:26
  • @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. – David Addoteye Feb 20 '16 at 16:30
  • @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`. – AJ Richardson Oct 27 '16 at 14:39
  • This also disables css animations. $animateProvider.classNameFilter or $animate.enabled, like suggested in the other answers, solves the issue in question without drawbacks. – Vargr Mar 19 '19 at 14:23
  • 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 explanation – David Addoteye Mar 21 '19 at 01:21
  • 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. – Vargr Mar 22 '19 at 14:29
  • @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... – Sergey Apr 13 '22 at 19:24
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);
    };
});
fracz
  • 20,536
  • 18
  • 103
  • 149
user1750709
  • 563
  • 3
  • 4
  • 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! – Mattygabe Aug 18 '15 at 16:03
  • 2
    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);` – gss Oct 07 '16 at 21:11
  • Apologies I see that's only applicable to 1.4.x+, the code above is correct for previous versions. – gss Oct 07 '16 at 21:18
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;
  }
}
Kerumen
  • 4,193
  • 2
  • 19
  • 33
Chris Barr
  • 29,851
  • 23
  • 95
  • 135
  • 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. – Eric Rini Mar 10 '15 at 13:33
  • This is the trickiest answer. Doing it with css is more better than messing with js. – manas Apr 03 '15 at 14:12
  • Please look at @Blowsie answer, that is the more generic and correct way to deal with this – edrian Feb 17 '16 at 17:50
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!

Betty St
  • 2,741
  • 21
  • 33
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. */
robro
  • 1,730
  • 23
  • 26
-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.