Remove an element whilst enter animation is still running - javascript

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

Related

jQuery .fadeOut method on and element that is being appended after DOM load

(I am 9 weeks into a boot camp, so I apologize for the potentially rudimentary nature of this...)
I am appending an element to the DOM (a button) within a conditional:
$('.buttonsAndInputs').append(`<button id="clearHistoryButton">Clear All</button>`);
When this button is clicked, it runs through a series of functions to empty an array and clear some other content off the DOM. I would like to use the .fadeOut method of jQuery to remove THE BUTTON.
I have this in a subsequent function:
$('#clearHistoryButton').remove();
I would like to:
$('#clearHistoryButton').fadeOut(1000);
...so that it disappears in a fancy fashion.
It's not working - it simply waits one second and then - POOF - is gone.
This is my first question. This community has been ESSENTIAL in my growth in this realm and, as always, I appreciate all of you so very much.
Did you try transition: opacity 1s in your CSS ?
Advantage:
Hardware accelerated (GPU), i.e. it doesn't bother your main processor (CPU) with this task, whereas jQuery's fadeOut() function is software based and does take CPU resources for that effect.
Steps:
Add transition: opacity 1s to your CSS rules of the desired button element
here: ( #clearHistoryButton )
Add a CSS rule with button.fadeMeOut with opacity: 0
Add a simple jQuery function to add the class ".fadeMeOut" at click
Then remove button with setTimeout(function(){$('#clearHistoryButton').remove()},1000)
Run code snippet
$(function() { // Shorthand for $( document ).ready()
$("#clearHistoryButton").on( "click", function() {
// first: fade out the button with CSS
$(this).addClass("fadeMeOut");
// then: after fadeOut effect is complete, remove button from your DOM
setTimeout(function(){
$('#clearHistoryButton').remove();
},1000);
});
});
button {
opacity: 1;
-webkit-transition: opacity 1s;
-moz-transition: opacity 1s;
transition: opacity 1s;
}
button.fadeMeOut {
opacity: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="clearHistoryButton">Press to hide me</button>

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;
}

How can I trigger ng-move after a splice?

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.

Adding class to transition element triggers too soon

I'm trying to animate some elements on my page. One of the properties I need to animate is bottom, however, I also need to be able to reposition the element without it animating, that's why I added a seperate class to it: .anim
.slideshow_footer {
position: absolute;
bottom: 0;
left: 0;
right: 0;
color: #fff
}
.slideshow_footer.anim {
-webkit-transition:bottom 0.3s ease-out;
-moz-transition:bottom 0.3s ease-out;
-o-transition:bottom 0.3s ease-out;
-ms-transition:bottom 0.3s ease-out;
transition:bottom 0.3s ease-out;
}
In my Javascript, I do the following:
var footer = $('#footer');
// do some magic with the footer
// ...
// ...
setCss(footer, 'bottom', -100); // position it so it's hidden, this should be immediate
addClass(footer, 'anim'); // add the animation class
setCss(footer, 'bottom', ); // animate the footer sliding in
Note that I'm not using jQuery or anything, it's an inhouse javascript framework.
I have found a workaround that solves the problem, but it's extremely ugly:
var footer = $('#footer');
// do some magic with the footer
// ...
// ...
setCss(footer, 'bottom', -100); // position it so it's hidden, this should be immediate
addClass(footer, 'anim'); // add the animation class
setTimeout(function() {
setCss(footer, 'bottom', ); // animate the footer sliding in
}, 0); // even no timeout works...
Can anyone explain to me what is happening and how this should best be solved? Possibly changing the addClass and setCss functions?
To answer my own question:
Using a timeOut is the correct approach.
The browser doesn't update the visible HTML until the entire JavaScript is done. If it did, setting "right" after "bottom" would move the element twice. From the perspective of the browser, the element instantly gains both "anim" and bottom 0. setTimeout with 0 timeout tells the browser to execute the code as soon as possible, but not in the same round of JavaScript.
The workaround is actually adopted by many people as an "asynchronous" way to run codes

How does Google achieve the fading effect on the home page?

If you go to google.com, you notice the menu on top slowly appears once you have mouse over the page. I was wondering what does Google use to control the fading effect?
[edit] since I don't use jQuery, I don't want to include it just to use this feature
There are two ways.
Javascript
Works in most browsers.
Gradually change the CSS opacity attribute of an element using Javascript. That's easiest with a good framework like jQuery, but is quite simple to do yourself.
function fadeIn() {
var element = document.getElementById("someID");
var newOpacity = element.style.opacity + 0.05;
element.style.opacity = newOpacity;
if (newOpacity < 1) {
window.setTimeout(fadeIn, 50);
}
}
Pure CSS
Only supported in Webkit at the moment.
#someID {
opacity:0;
-webkit-transition: opacity 1s linear;
}
#someID:hover {
opacity:1;
}
For an example have a look at the Surfin' Safari blog.
You could use jQuery and add an onmousemove callback on the tag that fades a hidden div with id "mymenu" in, something like:
$("html").one("mousemove", function() {
$("#mymenu").fadeIn("slow")
});
Warning: this was typed here, so I dunno if it compiles ootb.
I've never looked at it, but it's only logical to assume that there's a timer that gets started at load time for the page, and that adjusts either the alpha for the specified element or the opacity of another element that overlays it, in that element's CSS. Every timer tick, the numbers get turned up/down a little and the text becomes a bit more legible. When full visibility is reached, the timer is turned off.
JQuery is a finished, ready to use implementation of this in a cross-platform compatible package. You just add it, stir it up and it's done.
If you choose not to take the advice of the other answers, you'll have to research and implement the strategy from my top paragraph on your own. Good luck!
This is actually a rather complex thing to do because of the cross browser differences. The basics are something like the following:
Get the current opactity of the element as float.
Determine the ending opacity as float.
Determine your rate speed - i dont know what this should be in raw terms - somthing like .01/ms maybe?
Use a setInterval to fire a function that increases the opacity by your rate where: setInterval(function(){myElement.style.opacity = parseFloat(myElement.style.opacity)+0.01;}, 1); Somewhere in ther though you need to check if youve reached the endpoint of your animation and shutdown your interval.
I would think that they set the initial opacity of the elements other than the search box to zero. When the mouseover event is fired, the elements' opacity is gradually increased to 1.
Edit: In code it would look something like this:
var hiddenStuff = document.getElementByClassName("hiddenStuff");
var interval=document.setInterval(function() {
for (var i=0; i<hiddenStuff.length;i++){
hiddenStuff[i].style.opacity+=0.1
}
if (hiddenStuff[1].style.opacity===1){
window.clearInterval(interval);
}
}, 100);
You may need to tweak the parameters to get a smooth animation.
#Georg, that example works on Firefox 3.5 too. :-)
Demo: PURE CSS http://jsfiddle.net/6QS2a/1/
</div>
css:
.item {
height:150px;
width:150px;
border-radius:100%;
background:skyblue;
-webkit-transition: opacity 1s ease-in-out;
-moz-transition: opacity 1s ease-in-out;
-ms-transition: opacity 1s ease-in-out;
-o-transition: opacity 1s ease-in-out;
transition: opacity 1s ease-in-out;
opacity:0.2;
}
.item:hover {
opacity: 1;
}

Categories