Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop Angular Animation from happening on ng-show / ng-hide

In my AngularJS application I'm using fontawesome for my loading spinners:

<i class="fa fa-spin fa-spinner" ng-show="loading"></i>

I'm also using AngularToaster for notification messages which has a dependency on ngAnimate. When I include ngAnimate in my AngularJS application, it messes up my loading spinners by animating them in a weird way. I want to stop this from happening but cant find a way to disable the animation on just these loaders (it would also stink to have to update every loader I have in my app).

Heres a plunkr showing my exact problem.

http://plnkr.co/edit/wVY5iSpUST52noIA2h5a

like image 214
Chris Lees Avatar asked Jul 07 '14 18:07

Chris Lees


People also ask

How do I disable ng animation?

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. Simply add the ng-animate-disabled class to any elements you want to be ignored by ng-animate.

Can we use ng-show and Ng-hide together?

First of all, the two directives can trip over each other( see this JSFiddle, as provided by Joel Skrepnek), and is generally just bad design. You can use a function, another field or just some more inline-logic.

What is Ng-show and Ng-hide?

The ng-show directive shows or hides the given HTML element based on the expression provided to the ng-show attribute. The ng-hide directive shows or hides the given HTML element based on the expression provided to the ng-hide attribute .

What is Ng-hide in angular?

Definition and Usage. The ng-hide directive hides the HTML element if the expression evaluates to true. ng-hide is also a predefined CSS class in AngularJS, and sets the element's display to none .


3 Answers

I think the best way to do this is to use the $animateProvider.classNameFilter which will allow you to filter items to animate or in this case not to animate. We'll do something like:

 $animateProvider.classNameFilter(/^((?!(fa-spinner)).)*$/);  //$animateProvider.classNameFilter(/^((?!(fa-spinner|class2|class3)).)*$/); 

Demo:

http://plnkr.co/edit/lbqviQ87MQoZWeXplax1?p=preview

Angular docs state:

Sets and/or returns the CSS class regular expression that is checked when performing an animation. Upon bootstrap the classNameFilter value is not set at all and will therefore enable $animate to attempt to perform an animation on any element. When setting the classNameFilter value, animations will only be performed on elements that successfully match the filter expression. This in turn can boost performance for low-powered devices as well as applications containing a lot of structural operations.

As another answer per the comment with the no-animate directive, you could write an ng-show directive that will run at a higher priority and disable the animation. We will only do this if the element has the fa-spinner class.

  problemApp.directive('ngShow', function($compile, $animate) {     return {       priority: 1000,       link: function(scope, element, attrs) {          if (element.hasClass('fa-spinner')) {           // we could add no-animate and $compile per            // http://stackoverflow.com/questions/23879654/angularjs-exclude-certain-elements-from-animations?rq=1           // or we can just include that no-animate directive's code here           $animate.enabled(false, element)           scope.$watch(function() {             $animate.enabled(false, element)           })          }       }     }   }); 

Demo: http://plnkr.co/edit/BYrhEompZAF5RKxU7ifJ?p=preview

Lastly, and similar to the above, we can use the no-animate directive if we want to make it a little more modular. In this case I'm naming the directive faSpin which you could do in the answer above. This is essentially the same only we are preserving the directive from the SO answer mentioned in the comment of the above codeset. If you only care about the fa-spin animation issues naming it this way works well, but if you have other ng-show animation problems you'd want to name it ngShow and add to the if clause.

  problemApp.directive('noAnimate', ['$animate',     function($animate) {       return {         restrict: 'A',         link: function(scope, element, attrs) {           $animate.enabled(false, element)           scope.$watch(function() {             $animate.enabled(false, element)           })         }       };     }   ])    problemApp.directive('faSpin', function($compile, $animate) {     return {       priority: 1000,       link: function(scope, element, attrs) {          if (element.hasClass('fa-spinner')) {           element.attr('no-animate', true);           $compile(element)(scope);          }       }     }   }); 

Demo: http://plnkr.co/edit/P3R74mUR27QUyxMFcyf4?p=preview

like image 100
lucuma Avatar answered Sep 28 '22 08:09

lucuma


I had a similar problem where my icon would keep spinning until the animation finished, even after the $scope variable turned off. What worked for me was to wrap the <i> fa-icon element in a span.

<span ng-if="loading"><i class="fa fa-refresh fa-spin"></i></span> 

Try it!

like image 20
internet-nico Avatar answered Sep 28 '22 08:09

internet-nico


I've found an easier way.

<i class="fa fa-spinner" ng-show="loading" ng-class="{'fa-spin' : loading}"></i>

Forked plunker: http://plnkr.co/edit/mCsw5wBL1bsLYB7dCtQF

I did run into another small issue as a result of doing this where the icon would appear out of position if it spun for more than 2 seconds, but that was caused by the 'ng-hide-add-active' class, so I just added in my css:

.fa-spinner.ng-hide-add-active {
    display: none !important;
}

and that took care of it.

EDIT: Nico's solution is a slightly cleaner version of this, so I'd consider using his.

like image 27
James Fiala Avatar answered Sep 28 '22 07:09

James Fiala