How to fadeIn element on page load instead of "appear"? - javascript

Im a really huge noob on jquery, I need to figure out how to change this code:
$('.social li').appear();
$(document.body).on('appear', '.social li', function(e, $affected) {
var fadeDelayAttr;
var fadeDelay;
$(this).each(function(){
if ($(this).data("delay")) {
fadeDelayAttr = $(this).data("delay")
fadeDelay = fadeDelayAttr;
} else {
fadeDelay = 0;
}
$(this).delay(fadeDelay).queue(function(){
$(this).addClass('animated').clearQueue();
});
})
});
to work in the way that it would start animation as soon as someone enters the landing page, right now it works good on everything besides IE10 and IE11, was told to change it to load by default not on "appear" but I tried document ready/load and I can't get it to work...

You could try fading all list items into view, each with a progessing 250ms delay:
$(window).load(function() {
$('.social li').hide().each(function(i) {
$(this).delay((i + 1) * 250).fadeIn(2000);
});
});
EDIT:
Using the same logic as your previous code to refactor, use the window.load method since the load event fires at the end of the document loading process. At this point, all of the objects in the document are in the DOM, and all the images and sub-frames etc have finished loading. So use this event to do the fading in animation of the list items into view, where their initial state will be hidden.
You have two variables declared fadeDelayAttr and fadeDelay but I noticed that only fadeDelay is being used, so fadeDelayAttr can be discarded. Also, this part of the code:
if ($(this).data("delay")) {
fadeDelayAttr = $(this).data("delay")
fadeDelay = fadeDelayAttr;
} else {
fadeDelay = 0;
}
can be simplified as the null-coalescing operator using a logical OR (||):
var fadeDelay = $(this).data("delay") || 0;
Since the fadeDelay variable gets its value from the data-delay attribute, this can then be passed in as an argument for the delay method and finally the refactored code will look like this:
$(window).load(function() {
$('.social li').hide().each(function() {
var fadeDelay = $(this).data("delay") || 0;
$(this).delay(fadeDelay).fadeIn(2000);
});
});
Working Demo

Related

Detecting the end of a overflow-x:scroll element and add a class before animation

As the title suggests I want to detect the start and end of a scrollable element built using overflow.
The following code works:
var scrollAmount = 150;
var scrollBox = $('.js-compare_scroll');
var arrowLeft = $('.js-compare_scroll_left');
var arrowRight = $('.js-compare_scroll_right');
var inactive = 'm-inactive';
$(arrowLeft).on('click', function () {
$(this).parent().find(scrollBox).stop().animate({
scrollLeft: '-='+scrollAmount
}, function() {
arrowRight.removeClass(inactive);
if(scrollBox.scrollLeft() === 0) {
arrowLeft.addClass(inactive);
}
});
});
$(arrowRight).on('click', function () {
$(this).parent().find(scrollBox).stop().animate({
scrollLeft: '+='+scrollAmount
}, function() {
arrowLeft.removeClass(inactive);
if(scrollBox.scrollLeft() + scrollBox.innerWidth() >= scrollBox[0].scrollWidth) {
arrowRight.addClass(inactive);
}
});
});
However the class to style the inactive colour of the arrows only appears once the animation completes. I need to add the class before the animation completes because it has a delay. I believe by default it is 400.
Is there anyway to detect this and apply the arrow classes where needed?
Thanks.
Came back from a break and realised I should take the checking if its at the end off the click event and onto a scroll event. This works a lot better now.

How to not re-render the whole list in Mithril

I've used react for quite some time and wanted to try out Mithril.js.
Went through the documentation and the examples and liked what I saw, so I said I should get my hands dirty and start coding!
I have a smiple API call that receives a JSON data and then outputs ul list with all the items. I've integrated GSAP TweenMax for animations and what I'm trying to achieve is very simple - I fade everything in, on onload and then onclick I want to fade to fade an element out and remove it from DOM / data.
What seems to be happening is that the element is fading out, the whole ul list is being re-rendered and that element remains in the DOM with 0 opacity:
var Item = {
list: function() {
return m.request({method: 'GET', url: '/api/items'});
}
}
var dm = {
controller: function(data) {
var items = Item.list();
return {
items: items,
remove: function(item) {
items().data.splice(items().data.indexOf(item), 1);
}
}
},
view: function(ctrl) {
return m('ul', [
ctrl.items().data.map(function(item, id){
return m('li',{
key: id,
config: fadesIn,
onclick: fadeOut(ctrl.remove.bind(this, item))
}, item.title);
})
]);
}
}
var fadesIn = function(element){
var tl = new TimelineMax();
tl.from(element, .5, {opacity: 0});
}
var fadeOut = function(callback) {
return function(e) {
m.redraw.strategy('none');
TweenMax.to(e.target, .5, {opacity: 0, onComplete: function() {
m.startComputation();
callback();
m.endComputation();
}});
}
}
m.mount(document.getElementById('test'), dm);
I'm very new.. started reading up just yesterday.
Getting animation libraries to work with Mithril can be tricky. When libraries manipulate DOM state the synchronization with Mithril state can be broken.
Fortunately that wasn't the case: What you're missing is the isInitialized parameter for the config function, which is false only on the first call. Testing for that makes the fade-in only happen once:
var fadesIn = function(element, isInit){
if(isInit) return;
var tl = new TimelineMax();
tl.from(element, .5, {opacity: 0});
}
In this simple example the redrawing can also be simplified, I've made a fiddle with a working example:
http://jsfiddle.net/ciscoheat/dkyc0ryc/
Since there are no DOM manipulations a call to m.redraw is enough to remove the div from DOM, but you're probably right in using start/endComputation when things get more complex. I would even move m.startComputation above the TweenMax.to call to make it extra safe, but if many other things are happening at the same time, that may block other redraws. You have to find a balance. :)
The call to m.redraw.strategy isn't needed in any case, I think. It's mostly used when you want nothing at all to happen (synchronously as well), but an async animation is starting so it won't have any effect.
Edit: Found another problem, the key cannot be set to the index of the map function, then it will change when an item is removed, messing up the redraw. I've updated the fiddle to use item.title as key instead.

Does jquery trigger slidedown animation on an element that is already slidedown?

Well I hope the question is self-explanatory. I have the following code:
$(window).scroll(function () {
var scrollTop = $(window).scrollTop();
if (scrollTop > sliderTop) {
$('#slider').slideDown(1000);
} else {
$('#slider').slideUp(1000);
}
});
If I scroll down after a certain point the slideDown function will be called continuously. does JQuery animates it over and over again or is it smart enough to know that the element is already slide down? (currently I'm using a flag to check whether its already slide down).
The animation won't run again. See lines 459-468 in effect.js in the jquery src
doAnimation = function() {
// Operate on a copy of prop so per-property easing won't be lost
var anim = Animation( this, jQuery.extend( {}, prop ), optall );
// Empty animations, or finishing resolves immediately
if ( empty || data_priv.get( this, "finish" ) ) {
anim.stop( true ); // ** here - stopping right after started.
}
};
doAnimation.finish = doAnimation;
But I would still recommend against it to improve code readability. just use a boolean, it doesn't hurt...

jQuery wait for an action to complete on different functions

I have created a newsfeed. The feed switches every 2 seconds. You can also manually switch left/right, or click the panel from the squares at the bottom. The switching between slides is down using jQuery UI Slide.
Right now, if you are in the middle of a slide, and you click left/right/squares, then another slide occurs on top of the existing, still going slide and the whole system is messed up.
How can I prevent other actions occurring if a slide/switch is already in progress?
This is my code:
$(document).ready(function(){
newsfeedTimer = setInterval(newsfeed, displayDuration);
// Manual change of feed (LEFT)
$('#newsfeeds_wrapper > .left').click(function(event){
event.stopPropagation();
feedLeft();
clearInterval(newsfeedTimer);
newsfeedTimer = setInterval(newsfeed, displayDuration);
});
// Very similar code for feed right
// Ignore the other method of switching (if it works for above, I can implement it for this one)
});
function newsfeed() {
feedRight();
}
// Feed to the Right
// jump is used to jump multiple newsfeed instead of one at a time
function feedRight(jump)
{
jump = typeof jump !== 'undefined' ? jump : 1;
var current = $('.newsfeed:first');
var next = $('.newsfeed:nth(' + jump + ')');
current.hide('slide',{duration: transitionDuration}, function(){
// Append as many needed
for( var i = 0; i < jump; i++ ) {
$('.newsfeed:first').appendTo('#newsfeeds');
}
next.show('slide',{direction : 'right' , duration: transitionDuration});
}
I don't want to stop() an animation! I want to disable changing the slides IF there is animation happening!!
without seeing the full breadth of the code, I am shooting myself in the foot here. But here is a direction I would take it. You could also have two functions, one to bind, another to unbind. When animation is initiated, you unbind the left/right controls. When stopped, you bind. Or, set a global variable... ala.
var config = {'inProgress': false};
$('#newsfeeds_wrapper > .left').click(function(event){
if(!config.inProgress){
event.stopPropagation();
feedLeft();
clearInterval(newsfeedTimer);
newsfeedTimer = setInterval(newsfeed, displayDuration);
}
});
in your animation function. Seems like when you cut/paste, some of the code is lost, so lets just assume some animation.
when you enter your animation functions, set config.inProgress = true;
function feedRight(jump)
{
config.inProgress = true;
// removed your code, but just using for simplicity sake
// added a callback
next.show('slide',{direction : 'right' , duration: transitionDuration},
function() {
// Animation complete. Set inProgress to false
config.inProgress = false;
});
)
}

Javascript fade in doesn't visibly animate

So I've created the following function to fade elements in and passed in a div that I want to fade in which in this case is an image gallery popup that I want to show when a user clicks an image thumbnail on my site. I'm also passing in a speed value (iSpeed) which the timeout uses for it's time value. In this case I'm using 25 (25ms).
I've stepped through this function whilst doing so it appears to be functioning as expected. If the current opacity is less than 1, then it is incremented and it will recall itself after the timeout until the opacity reaches 1. When it reaches one it stops fading and returns.
So after stepping through it, I take off my breakpoints and try to see it in action but for some reason my gallery instantly appears without any sense of fading.
var Effects = new function () {
this.Fading = false;
this.FadeIn = function (oElement, iSpeed) {
//set opacity to zero if we haven't started fading yet.
if (this.Fading == false) {
oElement.style.opacity = 0;
}
//if we've reached or passed max opacity, stop fading
if (oElement.style.opacity >= 1) {
oElement.style.opacity = 1;
this.Fading = false;
return;
}
//otherwise, fade
else {
this.Fading = true;
var iCurrentOpacity = parseFloat(oElement.style.opacity);
oElement.style.opacity = iCurrentOpacity + 0.1;
setTimeout(Effects.FadeIn(oElement, iSpeed), iSpeed);
}
}
}
Here's where I'm setting up the gallery.
this.Show = function (sPage, iImagesToDisplay, oSelectedImage) {
//create and show overlay
var oOverlay = document.createElement('div');
oOverlay.id = 'divOverlay';
document.body.appendChild(oOverlay);
//create and show gallery box
var oGallery = document.createElement('div');
oGallery.id = 'divGallery';
oGallery.style.opacity = 0;
document.body.appendChild(oGallery);
//set position of gallery box
oGallery.style.top = (window.innerHeight / 2) - (oGallery.clientHeight / 2) + 'px';
oGallery.style.left = (window.innerWidth / 2) - (oGallery.clientWidth / 2) + 'px';
//call content function
ImageGallery.CreateContent(oGallery, sPage, iImagesToDisplay, oSelectedImage);
//fade in gallery
Effects.FadeIn(oGallery, 25);
}
Could anyone help me out?
Also, I'm using IE10 and I've also tried Chrome, same result.
Thanks,
Andy
This line:
setTimeout(Effects.FadeIn(oElement, iSpeed), iSpeed);
calls Effects.FadeIn with the given arguments, and feeds its return value into setTimeout. This is exactly like foo(bar()), which calls bar immediately, and then feeds its return value into foo.
Since your FadeIn function doesn't return a function, that would be the problem.
Perhaps you meant:
setTimeout(function() {
Effects.FadeIn(oElement, iSpeed);
}, iSpeed);
...although you'd be better off creating that function once and reusing it.
For instance, I think this does what you're looking for, but without recreating functions on each loop:
var Effects = new function () {
this.FadeIn = function (oElement, iSpeed) {
var fading = false;
var timer = setInterval(function() {
//set opacity to zero if we haven't started fading yet.
if (fading == false) { // Consider `if (!this.Fading)`
oElement.style.opacity = 0;
}
//if we've reached or passed max opacity, stop fading
if (oElement.style.opacity >= 1) {
oElement.style.opacity = 1;
clearInterval(timer);
}
//otherwise, fade
else {
fading = true;
var iCurrentOpacity = parseFloat(oElement.style.opacity);
oElement.style.opacity = iCurrentOpacity + 0.1;
}
}, iSpeed);
};
};
Your code has a lot of problems. The one culpable for the element appearing immediately is that you call setTimeout not with a function but with the result of a function, because Effects.FadeIn will be executed immediately.
setTimeout(function(){Effects.FadeIn(oElement, iSpeed)}, iSpeed);
will probably act as you intend.
But seriously, you probably should not re-invent this wheel. jQuery will allow you to fade elements in and out easily and CSS transitions allow you to achieve element fading with as much as adding or removing a CSS class.
T.J. and MoMolog are both right about the bug: you're invoking the Effects.FadeIn function immediately before passing the result to setTimeout—which means that Effects.FadeIn calls itself synchronously again and again until the condition oElement.style.opacity >= 1 is reached.
As you may or may not know, many UI updates that all take place within one turn of the event loop will be batched together on the next repaint (or something like that) so you won't see any sort of transition.
This jsFiddle includes the suggested JS solution, as well as an alternate approach that I think you may find to be better: simply adding a CSS class with the transition property. This will result in a smoother animation. Note that if you go this route, though, you may need to also include some vendor prefixes.

Categories

Resources