Angular ng-animate when using the same ui-view - angularjs

In parent template I'm specifying ui-view where the child view should appear, I also include animation, like this:
<div class="am-fade-and-slide-bottom" ui-view></div>
So I want animation to appear when something has been put ten in this view. And it works! And if I remove that ui-view (well, go to the previous state when using ui-router), I get animation of hiding that view.
The problem is, that when I'm changing the content of ui-view, I get repeated animations of hiding-and-showing, though I want to to stay without animation this time (as I have loading indicator on the template which goes inside ui-view).
How would I do that?
This is class .am-fade-and-slide-bottom from the Angular Motion library:
.am-fade-and-slide-bottom {
animation-duration: #fade-and-slide-duration;
animation-timing-function: #fade-and-slide-timing-function;
animation-fill-mode: backwards;
&.am-fade-and-slide-bottom-add, &.ng-hide-remove, &.ng-move {
animation-name: fadeAndSlideFromBottom;
}
&.am-fade-and-slide-bottom-remove, &.ng-hide {
animation-name: fadeAndSlideToBottom;
}
&.ng-enter {
visibility: hidden;
animation-name: fadeAndSlideFromBottom;
animation-play-state: paused;
&.ng-enter-active {
visibility: visible;
animation-play-state: running;
}
}
&.ng-leave {
animation-name: fadeAndSlideToBottom;
animation-play-state: paused;
&.ng-leave-active {
animation-play-state: running;
}
}
}

Related

Problems with ref focus using componentDidUpdate + opacity and visibility animation in css

I'm trying to focus() an input inside a modal right after it opens using the modal's componentDidUpdate().
This is the CSS I'm using for the modal root element:
.auth-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
visibility: hidden;
opacity: 0;
transition: visibility 400ms, opacity 400ms;
&.auth-modal_is-opened {
visibility: visible;
opacity: 1;
}
}
As you can see, it has visibility: hidden; and opacity: 0; at first.
Then I have this in the modal component:
componentDidMount() {
this.emailInput.focus();
}
componentDidUpdate() {
this.emailInput.focus();
}
The componentDidMount() hook works as intended, the input gets focused, but the componentDidUpdate() hook does not work (as though it gets called, only the focus() doesn't work as intended).
I've managed to find the reason and it happens to be the CSS animation. If I remove the visibility animation it works (but the animation breaks, of course). I've also managed to make it work using a setTimeout() inside the hook as bellow:
componentDidUpdate() {
setTimeout(() => {
this.emailInput.focus();
}, 100);
}
This also works, but feels super hackish.
Is there any better way to achieve this? (I'm currently setting a timeout as a hack solution)

ngAnimate doesn't animate transitions

I'm writing and app and ngAnimate stopped working at some point. I'm trying to debug it and cut down my app to this very minimal example where there's nothing more happening than animation when pushing a button. Still, I can't find out why it's not working. I'm injecting the ngAnimate as it's supposed to and I also have script-tag to include the source.
var searchApp = angular.module('searchApp', ['ngAnimate'])
http://plnkr.co/edit/ZJIF6BGs0ORr3S6YnJwG?p=preview
Anyone can see what I'm doing wrong? It must be some very obvious thing because the app is now so simple... spent hours trying to see it.
The issue is with your CSS not with Angular.
Here's a working version
Problem one is that .testiDiv .ng-hide is not valid in this situation, it implies that you're expecting .ng-hide to be within .testiDiv rather than on it.
Problem two is that the animation was on the wrong class, it should be related to the animation classes Angular automatically applies on elements using ng-show / ng-hide.
.testiDiv {
background-color: black;
width: 100px;
height: 100px;
opacity: 1;
}
.testiDiv.ng-hide {
opacity: 0;
}
.testiDiv.ng-hide-add, .testiDiv.ng-hide-remove {
-webkit-transition:all 1s linear;
-moz-transition:all 1s linear;
-o-transition:all 1s linear;
transition:all 1s linear;
}

ngAnimateSwap limitations

I have used ngAnimateSwap to translate elements horizontally, vertically. However are other types of animations supported, such as opacity (fade-in and fade-out?)
When I modify the example that appears here animateSwap to use opacity instead of the top value, then the animation does not occur. Is this expected?
I was able to get it working using opacity. You have to play around with the css and understand what css element does what. Here's a plunkr of animateSwap being used with an opacity transition.
The original css is:
.swap-animation.ng-enter {
top:-250px;
}
.swap-animation.ng-enter-active {
top:0px;
}
.swap-animation.ng-leave {
top:0px;
}
.swap-animation.ng-leave-active {
top:250px;
}
I changed that to the following and I now have a crossfade working just fine:
.swap-animation.ng-enter {
top:0px;
opacity:0;
}
.swap-animation.ng-enter-active {
top:0px;
opacity:1;
}
.swap-animation.ng-leave {
top:0px;
opacity:1;
}
.swap-animation.ng-leave-active {
top:0px;
opacity:0;
}

How to adjust the height for fadeInUp in ng-animate or Animate.css?

This may be a very simple question for most of you, but I'm having a very difficult time figuring this out.
I have a data table that's big enough to run the entire screen. It's very specific so pagination is out of question. The issue that I'm having is with animation. I have the table inside div with ng-view. I want fadeInUp animation such that the fadeInUp seems to be from around 60-100px from the top. However, the current fadeInUp comes sliding up from the bottom of the screen which I do not want. How can I make it so that it slides up from the desired height?
<div ng-view class="content-wrapper ng-fadeInUp">
[ng-view].ng-enter{
animation:fadeInUp 1s;
}
This is what's making it slide up from the bottom of the screen. I tried using "Animate.css" which did the same thing. I want it so that it seems it's barely sliding up. Just a small hint of animation instead of the full slide up.
Take the original CSS from example animate.css and modify it:
#keyframes fadeInUp {
from {
opacity: 0;
transform: translate3d(0, 100%, 0);
}
to {
opacity: 1;
transform: none;
}
}
.fadeInUp {
animation-name: fadeInUp;
}
Change the second parameter in translate3d to what you want, for example:
transform: translate3d(0, 20px, 0);
Demo: http://plnkr.co/edit/W5zsmhYkwXxYJbuft5pu?p=preview

How can I animate the movement of remaining ng-repeat items when one is removed?

I have a dynamic list of items using ng-repeat. When something happens an item may disappear. I have handled smoothly animating the removal of these items using ng-animate, but after they are gone, the remaining items simply snap to their new position. How can I animate this movement smoothly?
I've tried applying an "all" transition to the repeated class and using ng-move with no success.
You can achieve this by animating the max-height property. Check out this sample:
http://jsfiddle.net/k4sR3/8/
You will need to pick a sufficiently high value for max-height (in my sample, I used 90px). When an item is initially being added, you want it to start off with 0 height (I'm also animating left to have the item slide in from the left, as well as opacity, but you can remove these if they don't jibe with what you're doing):
.repeated-item.ng-enter {
-webkit-transition:0.5s linear all;
-moz-transition:0.5s linear all;
-o-transition:0.5s linear all;
transition:0.5s linear all;
max-height: 0;
opacity: 0;
left: -50px;
}
Then, you set the final values for these properties in the ng-enter-active rule:
.repeated-item.ng-enter.ng-enter-active {
max-height: 90px;
opacity: 1;
left: 0;
}
Item removal is a bit trickier, as you will need to use keyframe-based animations. Again, you want to animate max-height, but this time you want to start off at 90px and decrease it down to 0. As the animation runs, the item will shrink, and all the following items will slide up smoothly.
First, define the animation that you will be using:
#keyframes my_animation {
from {
max-height: 90px;
opacity: 1;
left: 0;
}
to {
max-height: 0;
opacity: 0;
left: -50px;
}
}
(For brevity, I'm omitting the vendor-specific definitions here, #-webkit-keyframes, #-moz-keyframes, etc - check out the jsfiddle above for the full sample.)
Then, declare that you will be using this animation for ng-leave as follows:
.repeated-item.ng-leave {
-webkit-animation:0.5s my_animation;
-moz-animation:0.5s my_animation;
-o-animation:0.5s my_animation;
animation:0.5s my_animation;
}
Basics
In case anyone is struggling with figuring out how to get AngularJS animations to work at all, here's an abbreviated guide.
First, to enable animation support, you will need to include an additional file, angular-animate.js, after you load up angular.js. E.g.:
<script type="text/javascript" src="angular-1.2/angular.js"></script>
<script type="text/javascript" src="angular-1.2/angular-animate.js"></script>
Next, you will need to load ngAnimate by adding it to the list of your module's dependencies (in the 2nd parameter):
var myApp = angular.module('myApp', ['ngAnimate']);
Then, assign a class to your ng-repeat item. You will be using this class name to assign the animations. In my sample, I used repeated-item as the name:
<li ng-repeat="item in items" class="repeated-item">
Then, you define your animations in the CSS using the repeated-item class, as well as the special classes ng-enter, ng-leave, and ng-move that Angular adds to the item when it is being added, removed, or moved around.
The official documentation for AngularJS animations is here:
http://docs.angularjs.org/guide/animations
TLDR: Jank is bad, do animations with transform. Check out this fiddle for css and demo.
Explanation
Note that animating height, max-height, top, ... is really bad performance wise because they cause reflows and thus jank (more information on html5rocks|high-performance-animations).
There is however a method getting this type of animation using only transforms by utilizing the sibling selector.
When elements are added there is one reflow because of the new item, all items below are transformed up so they stay at the same position and then the transformation is removed for a smooth slide-in.
In reverse when elements are removed they are transformed to the new position for a smooth slide-out and when the element is finally removed there is again one reflow and the transform is removed instantly so they stay at their position (this is also why it is important to only have transition set on ng-animate).
Alternatively to the example you could also do a transform: scaleY(0) on the deleted item and only transform: translateY() the siblings.
Caveat
Note that this snippet has trouble when multiple elements are removed in quick succession (before the previous animation has completed).
This can be fixed by having an animation time faster than the time a user takes to delete another item or by doing some more work on the animation (out of scope of this answer).
Finally some code
Note: apparently SO breaks the demo with multiple deletes - check out the fiddle to see it in work.
angular.module('app', ['ngAnimate'])
.controller('testCtrl', ['$scope', function($scope) {
var self = this;
self.items = [];
var i = 65;
for(; i < 72; i++)
{
self.items.push({ value: String.fromCharCode(i) });
}
self.addItem = function()
{
self.items.push({ value: String.fromCharCode(i) });
i++;
}
self.removeItemAt = function(index)
{
self.items.splice(index, 1);
}
}])
li
{
height: 48px;
width: 300px;
border: 1px solid lightgrey;
background-color: white;
position: relative;
list-style: none;
}
li.ng-enter,
li.ng-enter ~ li {
transform: translateY(-100%);
}
li.ng-enter.ng-enter-active,
li.ng-enter.ng-enter-active ~ li {
transform: translateY(0);
}
li.ng-animate {
z-index: -1;
}
li.ng-animate,
li.ng-animate ~ li {
transition: transform 0.6s;
}
li.ng-leave,
li.ng-leave ~ li {
transform: translateY(0);
}
li.ng-leave.ng-leave-active,
li.ng-leave.ng-leave-active ~ li {
transform: translateY(-100%);
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.23/angular-animate.js"></script>
<div ng-app="app" ng-controller="testCtrl as ctrl">
<ul>
<li ng-repeat="item in ctrl.items" ng-bind="item.value">
</li>
</ul>
<button ng-click="ctrl.addItem()">
Add
</button>
<button ng-click="ctrl.removeItemAt(5)">
Remove at 5
</button>
</div>

Resources