How do you animate ng-show? - angularjs

I would like to fade out a UL on ng-show=false. I add this css:
ul {
-webkit-transition: all 2s;
transition: all 2s;
}
.ng-show-remove,
.ng-show-add,
.ng-hide-remove,
.ng-hide-add {
display:block!important;
}
ul.ng-hide {
opacity: .2;
}
But when ng-show is set to false it just instantly disappears. How do I get it to fade out instead of instantly disappearing?
Click one of the li in this fiddle for a demonstration.

I've attached a fiddle solution.
A few things to note:
The angular version you included in your fiddle doesn't support the css animations. You'll need to update to the 1.2 version (which also requires you to include the angular-animate.js file and the ngAnimate module into your app)
var app = angular.module('foo', ['ngAnimate']);
Fiddle.

Related

Ionic v1 modal destroyed before leave animation is complete

When using the default slide-in-up animation for an Ionic (v1) modal, the modal leave animation looks perfect. But when substituting a different animation ( I am using slide-in-right) the modal is destroyed (i.e. removed from the DOM) before the leave animation is done. Here's my code:
JS:
//create the modal
$ionicModal.fromTemplateUrl('templates/my-modal.html', function(modal) {
$scope.myModal = modal;
}, {
scope: $scope,
animation: 'slide-in-right'
});
//show the modal
$scope.myModal.show()
//hide the modal
$scope.myModal.hide();
and the CSS (the timings are long just for debugging purposes):
.slide-in-right {
-webkit-transform: translateX(100%);
transform: translateX(100%); }
.slide-in-right.ng-enter, .slide-in-right > .ng-enter {
-webkit-transition: all cubic-bezier(0.1, 0.7, 0.1, 1) 2000ms;
transition: all cubic-bezier(0.1, 0.7, 0.1, 1) 2000ms; }
.slide-in-right.ng-enter-active, .slide-in-right > .ng-enter-active {
-webkit-transform: translateX(0);
transform: translateX(0); }
.slide-in-right.ng-leave, .slide-in-right > .ng-leave {
-webkit-transition: all linear 2800ms;
transition: all linear 2800ms; }
This causes a noticeable UX hiccup, since the modal is only half way through the leave animation before it just disappears. You can see this here:
http://codepen.io/frey1esm/pen/QvOQjO
The leave timing in this codepen is 2500ms so that's how long the modal should be visible as it slides out to the left. But it gets removed almost instantly. IS there a way to delay the removal of the modal from the DOM?
i dont know if there a good ionic answer to that
anyway my workaround will be custom class conditions
http://codepen.io/islam4hak/pen/JNOepN
on the ion modal use a condition class name
<ion-modal-view ng-class="GoingAway==1 ? 'slide-in-left ng-leave' : ' '">
and for the controller
$scope.GoingAway = 0;
$scope.CustomHide = function(e){
$scope.GoingAway = 1;
setTimeout(function(){
$scope.modal.hide();
$scope.GoingAway = 0;
},2600)
}
Hope that this work for you

Transition using ng-animate not working in 1.2.16

I'm trying to recreate the following transitions using ng-animate in angular v1.2.16 instead of v1.1.4 (used in fiddle).
If you update the angular lib in the fiddle to 1.2.16 the transitions no longer work. Why do they no longer work?
link to fiddle http://jsfiddle.net/angularjs_de/dxQqm/
html
<li ng-repeat="item in items" ng-animate="'repeat'">{{item}}</li>
css
.repeat-enter-setup, .repeat-leave-setup {
-webkit-transition:all linear 0.3s;
-moz-transition:all linear 0.3s;
-ms-transition:all linear 0.3s;
-o-transition:all linear 0.3s;
transition:all linear 0.3s;
}
.repeat-enter-setup { opacity:0; }
.repeat-enter-setup.repeat-enter-start { opacity:1; }
.repeat-leave-setup { opacity:1; }
.repeat-leave-setup.repeat-leave-start { opacity:0; }
Angular changed the way animations work in 1.2+.
Animation is now a separate module that needs to be added.
There is a very nice guide on 1.2+ animations found here:
http://www.yearofmoo.com/2013/08/remastered-animation-in-angularjs-1-2.html
Edit: In that link they also talk about what has changed from 1.1.5 to 1.2 it will help you understand the changes.
var app = angular.module('myApp', ['ngAnimate']);
app.controller('MainController', ['$scope', function ($scope) {
$scope.items = [1,2,3,4,5,6,7,8,9];
$scope.replaceItem = function() {
$scope.items.shift();
$scope.items.push(Math.floor(Math.random()*1000000000));
};
}]);
Solution in fiddle: http://jsfiddle.net/dxQqm/166

Angular animate not working correctly on first run when element is initially hidden

I am wiring up a status bar on my angular app, the purpose is when a request is made to the server the bar will show the response message, will have a background colour to denote success or error, and if it was successful to hide after a few seconds.
What I am seeing is that the first time this logic is run through after loading the page the animations are not run (both the fade in and timed fadeout fail to run), but only if the status bar element is initially hidden, if I set the ng-show variable to true on page load all the animations work as expected.
I did inspect the source via chrome's developer tools and during this first run the div has these classes alert-bar ng-hide-remove ng-hide-remove-active alert-bar-success ng-animate ng-hide after the animation should have been finished. When the animation does work the only classes present are alert-bar alert-bar-success ng-animate ng-hide.
The HTML:
<div class="alert-bar" ng-show="response.show" ng-class="(response.result == true) ? 'alert-bar-success' : 'alert-bar-danger'">
<div class="container">
<label>Message: {{response.message}}</label>
</div>
</div>
The CSS:
.alert-bar {
width: 100%;
margin-top: -20px;
margin-bottom: 20px;
}
.alert-bar-success {
background-color: #5cb85c;
border-color: #4cae4c;
color: #ffffff;
}
.alert-bar-danger {
color: #ffffff;
background-color: #d9534f;
border-color: #d43f3a;
}
.alert-bar.ng-hide-add, .alert-bar.ng-hide-remove {
-webkit-transition:all linear 0.3s;
-moz-transition:all linear 0.3s;
-o-transition:all linear 0.3s;
transition:all linear 0.3s;
display:block!important;
}
.alert-bar.ng-hide-add.ng-hide-add-active,
.alert-bar.ng-hide-remove {
opacity:0;
}
.alert-bar.ng-hide-add,
.alert-bar.ng-hide-remove.ng-hide-remove-active {
opacity:1;
}
The Controller:
controllers.controller("AppController", ['$scope', '$timeout', function($scope, $timeout) {
$scope.response = {};
$scope.response.received = function(message, result) {
$scope.response.message = message;
$scope.response.result = result;
$scope.response.show = true;
if (result == true) {
$timeout(function () {
$scope.response.show = false;
}, 4000);
}
};
}]);
This happens due to interplay between the animation code applied for both the ng-class and ng-hide directives. The only way I have made things like this work is to use separate <div> elements which are shown/hidden conditionally but that have static classes.
Here is a plunkr that demonstrates splitting the above into two <div> elements to create a working example for the problem in the question:
http://plnkr.co/edit/PFNGkOLKvs8Gx9h1T6Yk?p=preview
Alternatively, you could forego the use of ng-hide/ng-show entirely and use ng-class exclusively.
Edit: see http://plnkr.co/edit/JiLPc6cqiLHR21c64cCy?p=preview for a version that uses ng-class exclusively.
You don't need to use two divs. I guess the simplest solution is just putting animate css into class "ng-hide-add-active" only, not into "ng-hide-add". Like below:
.page-ready-animate.ng-hide-add-active {
-webkit-animation: 0.5s fadeOutDown;
animation: 0.5s fadeOutDown;
}

disable nganimate for some elements

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.
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.
There are two ways you can disbale animations in AngularJS if you have the module ngAnimate as a dependency on your module:
Disable or enable the animation globally on the $animate service:
$animate.enabled(false);
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.
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/
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>
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);
};
});
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;
}
}
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!
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. */
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.

Can ngAnimate be used without defining CSS3 classes or JavaScript?

Is it possible to use ngAnimate without any CSS3 or JavaScript? Let's say if you simply need to toggle the opacity, can you just do it in the markup?
<div ng-show='foo == 'yes'' ng-animate="show: 'opacity:1', hide: 'opacity:0'" >
</div>
Animation in the browser either needs to happen by (1) letting the browser's rendering engine handle it via CSS, or (2) controlling it yourself with JavaScript. So, somewhere, one of these two things needs to happen.
That said, you could build your own directive that builds the correct CSS and/or JavaScript on the fly and attaches/applies it to the given element, but I believe that using ngAnimate as provided is probably easier.
An example for those coming into ngAnimate for the first time:
HTML:
<div ng-show="foo == 'yes'" ng-animate="{show: 'fade'}"></div>
CSS:
.enter-fade {
-webkit-transition: 1s linear opacity;
-moz-transition: 1s linear opacity;
-o-transition: 1s linear opacity;
transition: 1s linear opacity;
opacity: 0;
}
.enter-fade.enter-fade-active {
opacity: 1;
}
Or, if you're supporting browsers that don't support CSS3 transitions, you can do the transition with JavaScript instead:
myModule.animation('fade', function() {
return {
setup : function(element) {
element.css({'opacity': 0});
},
start : function(element, done, memo) {
element.animate({'opacity': 1}, function() {
done();
});
}
};
});
You can find more information at these great Yearofmoo articles:
Animation in AngularJS
Enhanced Animation in AngularJS

Resources