How can I trigger ng-move after a splice? - javascript

I am using ng-animate and I have a list of entries iterated through using ng-repeat. When you make a selection on a particular entry, it disappears. I have defined .ng-move, .ng-move-active, .ng-leave, .ng-leave-active appropriately so that the .leave animation occurs when I perform a .splice() operation on my data, and the .move operation occurs when I reorder entries.
However, what I want is for when one of the entries is removed, the .ng-leave occurs on that entry while .ng-move slides them all up. I've found that .splice() doesn't trigger an .ng-move though, so I'm curious if there is a way to force that animation to happen after a .splice()?
Here is the html:
<div data-ng-repeat="entry in data" class="container card-drop card-shift">
<card data="entry"></card>
</div>
Here are the css classes:
.card-drop.ng-leave {
transition: 0.5s ease-in-out;
opacity: 1;
}
.card-drop.ng-leave.ng-leave-active {
transform: scale(0.5);
opacity: 0;
}
.card-shift.ng-move {
transition: 0.5s ease-in-out;
}
.card-shift.ng-move.ng-move-active {
transform: translateY(-284px);
}
And in the javascript the event I am concerned about is simply $scope.data.splice(index, 1);
EDIT: http://plnkr.co/edit/nz38XxPbV4Ycqdn3QYVP?p=preview
Above is the plunk for the issue I am referring to. Notice that when you click on an entry and it is spliced, the .ng-leave animation occurs but none of the ng-move animations do.

The solution was that there was no easy way to do this. Ultimately I ended up manipulating DOM elements' CSS from within the directive to provide the sliding animation, then instantaneously shifted them to their original spot at the same time as the splice, resulting in the animation I was after, albeit in a hacky way.

Related

Wait for class to be added before modifying styles

I'm trying to do something like this:
element.classList.add('animate-in')
element.style.transform = 'translateY(100px)';
Where the animate-in class has a transition: transform 1s property for animation. But when I run this it the element is translated 100px down but without the transition, seems like the transform property is modified before the class name can be added and take affect. I don't want to use setTimeout since it can be unreliable in animations. Is there any way to wait for the class to be added before modifying any styles?
I don't think we get any events for the 'application of styles' through JavaScript, which is pretty frustrating in this case...
I found this thread that's pretty helpful.
One thing to note: the animation will work even if you use setTimeout with 0 ms. What was the reason in particular that it messed with animations?
setTimeout(function(){
element.style.transform = 'translateY(100px)'
}, 0)
Also, if you set it up with an event, you can change the style directly and see the animation applied.
Here's the bin I was playing around with: https://jsbin.com/lofotutumu/edit?html,css,js,output
You don't really want to wait, but want the properties embedded with this new class to be applied.
And this can be done, synchronously, by triggering a reflow.
Some properties/functions need the DOM boxes to be recalculated in order to return their values. To do so, the browser has to trigger a reflow on the page, and hence will apply your new properties.
But note that this has a performance impact, particularly on complex pages, so use it with care.
element.classList.add('animate-in');
element.offsetTop; // trigger a reflow
element.style.transform = 'translateY(100px)';
.animate-in {
transition: transform 2s linear;
}
<div id="element">Hello</div>
Would creating a keyframe and adding that into your class suit your needs? E.g.
// This is your keyframe to animate your element
#keyframes translateDown {
0%{
transform:translateY(0);
}
100%{
transform:translateY(100px);
}
}
.animate-in{
animation: 2s linear translateDown both;
}

Remove an element whilst enter animation is still running

I have an animation which runs on any new item to a grid. Lets say this animation takes 5 seconds to run. Currently, if I try removing that element within the 5 seconds (so whilst the enter animation is still running), the item remains in the list until the enter animation finishes.
Looking at the docs, it says that this is by design:
You'll notice that when you try to remove an item
ReactCSSTransitionGroup keeps it in the DOM. If you're using an
unminified build of React with add-ons you'll see a warning that React
was expecting an animation or transition to occur. That's because
ReactCSSTransitionGroup keeps your DOM elements on the page until the
animation completes.
It ways that you need to add the following (updated to the relevant class names obviously) and it should work for the case described above:
.example-leave {
opacity: 1;
transition: opacity .5s ease-in;
}
.example-leave.example-leave-active {
opacity: 0.01;
}
I'm not finding this to be the case, even though I have the described leave classes, I'm finding that it is still waiting for the original enter animation to finish, is this behavior correct, how do I fix this?
Here is a video showing the quirk in question - https://www.youtube.com/watch?v=3oKerWlLZIE
If it makes a difference here is my classes:
.request-summary-item-holder-enter {
background-color: #F8F5EC;
transition: background-color 5s ease-in;
}
.request-summary-item-holder-enter.request-summary-item-holder-enter-active {
background-color: transparent;
}
.request-summary-item-holder-leave {
opacity: 1;
transition: opacity 0.05s ease-in;
}
.request-summary-item-holder-leave.request-summary-item-holder-leave-active {
opacity: 0.01;
}
Update:
Source code references:
Setting the state - https://github.com/avanderhoorn/Glimpse.Client.Prototype/blob/master/src/request/components/request-summary-view.jsx#L33
Usage of transition group and setting keys - https://github.com/avanderhoorn/Glimpse.Client.Prototype/blob/master/src/request/components/request-summary-list-view.jsx

Animation transitions behave differently for ng-hide-remove and ng-hide-add

I am trying to animate a <div> to slide-in/out from the left on a button click. I am using the angular framework and ng-showto control the <div> display/visibility, and adding transitions to the ng-hide set of styles.
I have successfully managed to have the div slide in from the left, however I can not get it to slide out (it simply dissappears after the specified delay). I have tried modifying several examples online to get the behavior I am after to no avail.
JSFiddle for anyone that wants to have a look
https://jsfiddle.net/mquinlan/0wcrcwxe/5/
You got that almost right except for removing the left:0 in the selectors for .animate-show.ng-hide-add.ng-hide-add-active, .animate-show.ng-hide-remove.ng-hide-remove-active.
.animate-show.ng-hide-add.ng-hide-add-active,
.animate-show.ng-hide-remove.ng-hide-remove-active {
-moz-transition: all ease 0.5s;
transition: all ease 0.5s;
}
Updated Fiddle: https://jsfiddle.net/vsj62g5r/

How to correctly wait until JavaScript applies inline Css

I have this jsFiddle. When the button is clicked, I want to put the red div behind the black one immediately, then start the animation.
var red = document.getElementById("red");
var button = document.getElementById("button");
button.addEventListener("click",function () {
red.style.zIndex = -1;
red.classList.remove("shifted");
});
However, as you can see, they seem to be occurring as two separate actions. I know I can use setTimeout to wait until the zIndex property is applied, but I do not know how long I am supposed to wait, and the duration perhaps differs from browsers to computers.
Should I create a loop that will check if zindex was applied? But this also sounds like an unintelligent solution. What is the correct way?
EDIT: I do not want to change the zIndex on the black div.
You can bind to the transitioned state of the element, something like this:
("#mySelector").bind("transitionend", function(){ 'yourcodehere' });
Also, here is some info on it:
https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_transitions
https://developer.mozilla.org/en-US/docs/Web/Reference/Events/transitionend
Without jQuery:
el.addEventListener("transitionend", updateTransition, true);
Edit:
There was some confusion as to the usage of:
-webkit-transition-duration: 1s;
This is applied like a styling as well. So anytime you make alterations to the element it is on, you are triggering this. You have TWO transition calls, one for setting the z-index, another for the movement.
Just put a
-webkit-transition-property: -webkit-transform;
into the #red and everything is fine. ;) This applies the transition only to specified property.
JSFIDDLE: http://jsfiddle.net/Qvh7G/.
The problem is with zIndex - the transform time delays the change in the zIndex.
You can simply force the duration for the transform property.
Replace:
-webkit-transition-duration: 1s;
With
-webkit-transition: -webkit-transform 1s; // ease-in;

Animating new ng-grid rows

How can I animate a newly created row in ng-grid?
What I would like is that when new data comes in from the server, it is added to the beginning of the grid, and that row then glows for a few seconds.
I've tried adding an ng-animate class to the rowTemplate for the grid, but that was unsuccessful:
$scope.gridOptions = {
data: 'myData',
rowTemplate: '<div style="height: 100%" class="reveal-animation"><div ng-style="{ \'cursor\': row.cursor }" ng-repeat="col in renderedColumns" ng-class="col.colIndex()" class="ngCell {{col.cellClass}}"><div class="ngVerticalBar" ng-style="{height: rowHeight}" ng-class="{ ngVerticalBarVisible: !$last }"> </div><div ng-cell></div></div></div>'
};
Where my reveal-animation (lifted straight from the ng-animate docs) is:
.reveal-animation.ng-enter {
-webkit-transition: 1s linear all;
transition: 1s linear all;
opacity: 0;
}
.reveal-animation.ng-enter.ng-enter-active {
opacity: 1;
}
But this does not appear to work for the grid.
Is there some way to accomplish this?
Here is a Plunker with my attempt
http://plnkr.co/edit/iR9voQaFRREi0pjNLQgc?p=preview
I added a <ul> at the bottom to show the behavior that I want (and to prove that ng-animate is working).
The proper way to animate this is by binding an animation to .ngRow i.e.:
/*
The animate class is apart of the element and the ng-enter class
is attached to the element once the enter animation event is triggered
*/
.ngRow.ng-enter {
-webkit-transition: 1s linear all; /* Safari/Chrome */
transition: 1s linear all; /* All other modern browsers and IE10+ */
/* The animation preparation code */
opacity: 0;
}
/*
Keep in mind that you want to combine both CSS
classes together to avoid any CSS-specificity
conflicts
*/
.ngRow.ng-enter.ng-enter-active {
/* The animation code itself */
opacity: 1;
}
The problem is that you are using unshift to push the values into the beginning of the array, but ng-grid still functions by adding a row at the bottom of the grid and rebinding all the rows such that, unintentionally, the first item in the grid is the one that gets the animation.
Here's the plunker for my fork which has the above css working - perhaps you can take it a step further: http://plnkr.co/edit/gNSM4FRMFcTtQtT6EU7b?p=preview
As a thought: maybe you can have the elements go into the data set as a normal push and re-order the grid by something that keeps them in reverse order. That might trick the grid into animating the newest thing in but keep the newest thing at the top of the grid.
To be honest, I have found that simply building my own grid and binding an ng-repeat to the tr was much easier than trying to fuss with other grid systems, especially ones like ng-grid where you don't get to control the behavior.

Categories