What determines the execution order of methods in jQuery chains? - javascript

HTML Code
<div id="foo">
<h1>foo</h1>
<p>Pellentesque habitant morbi tristique.</p>
</div>
<div id="bar">
<h1>bar</h1>
</div>
jQuery Code
$('#bar').click(function () {
$('#foo p').hide('slow').appendTo('#bar').show('slow');
})
Expected Result
When #bar is clicked
hide the p element in #foo
append p to #bar
show p which is now a child of #bar
Actual Result
append p to #bar
hide the p element in #foo
show p which is now a child of #bar
Questions
What determines the execution order of methods in jQuery chains?
How can I ensure that each event completes before the next starts?

To ensure you execute something AFTER an effect like hide or show, use a callback.
http://docs.jquery.com/Effects/show#speedcallback
To Add:
Vincent is right, the execution is actually
start hiding the p element in #foo
(SLOWLY)
append p to #bar (in a snap)
start showing p which is now a child of #bar (SLOWLY)
What you saw was the result of the effect
append p to #bar (executed)
hide the p element in #foo
(COMPLETED)
show p which is now a child of #bar
(COMPLETED)

The expected result is correct. The observed behaviour may be a result of hide('slow') which runs asynchronously. So it runs while the next action executes. So it appears as if p is appended to #bar first. You can try hide() without the slow to see if that makes a difference.

If you want to wait until each animation completes before doing the next step, use the animation callbacks detailed in the documentation:
$('#bar').click(function () {
$('#foo p').hide('slow', function(){
$(this).appendTo('#bar').show('slow');
});
});

show() and hide() are actually animation effects but when no arguments are passed they use an "instant" duration. However, due to the fact that they're implemented as animations, that means that they don't execute synchronously with the function chain. Thus, what you really should be using is a callback off of the hide() call to trigger a callback function which calls append() and then show().
http://docs.jquery.com/Effects/show
http://docs.jquery.com/Effects/hide

Hide is asynchronous. If you want to wait for it to finish, you need to put all the code you want to run after it into a callback function that you pass to hide as a parameter.

Pretty sure it's executed in the order you invoke it, it probably starts the hide part and a split second later it's appended to that other element but the animation part has already begun, it takes longer than a millisecond because you set it to 'slow' and it's jumping in opacity from 1 to 0, going from say 1 to .9 to .8 in milliseconds.
$.fn.hide = function() { alert('hiding'); return this; };
$.fn.appendTo = function() { alert('appending To') }
$('body').hide().appendTo('html')

You have to use callback if you want to queue the other methods run after the show hide thing like "Sixten Otto" has said. The animation of show hide will not wait for append method to execute. It starts a separate thread with setInterval while in the meantime, other code is invoked. So the result you got is not unexpected.

Related

How to make an onShow onHide event for jQuery for only applied element?

I am using the following code, to enable on-show and on-hide events. So, for example when I make a DIV visible, it will automatically call my custom function and do appropriate changes on the DIV at that moment automatically.
(function ($) {
$.each(['show', 'hide'], function (i, ev) {
var el = $.fn[ev];
$.fn[ev] = function () {
this.trigger(ev);
return el.apply(this, arguments);
};
});
})(jQuery);
The problem is, it is called when any other element inside that main DIV is show()ned too.
So, when I do
$('.mother').on('show',function(){
if(...){
$(this).find('.child').show();
} else {
$(this).find('.child').hide();
}
});
for
<div class="mother">
<div class="child"></div>
</div>
It goes to infinite loop, as in jQuery on() method requires a selector for the second parameter and it is triggered for an event that happens on the children too if that second parameter is omitted or null.
I couldn't define that second parameter.
So making it
$('.mother').on('show','.mother', function(){
does not work, as it is already the mother...
I do not want to type:
if(event.target != event.delegateTarget){return;}
to every single callback function and I couldn't do it in the plugin code too as it doesn't have event object there...
These were what I have tried.
How can I solve this?
What can be the alternatives?
I want to be able to bind onShow functions to specific elements which shall never be called on events those happen on it's children.
If you want to run a custom function after show / hide on some elements and on others not you shouldn't change the $.fn.show() / .hide() itself. Instead you can pass your function as a callback parameter to .show() / .hide():
function custom() {console.log('custom: ', this);}
$(".mother").show(custom); // ---> custom: <HTMLElement>
Note that the callback is executed after show / hide have finished. So if you call them with duration:
$(".mother").show(2000, custom);
custom is executed 2 seconds later.

How can I make sure my next image wont come up

How can I make sure that my next image will not come up until my first one has been completely hidden? It is written in Javascript and is a single line code, I wanted to make sure that the next one would not fade in before the last one fades out...since that causes the slider to distort. Here is the code:
$('.carousel_slider a:first-child').fadeOut().hide().next().fadeIn().show().end().appendTo('.carousel_slider');
How can I make sure that my next image will not come up until my first one has been completely hidden?
Here is a working example http://jsfiddle.net/pV57K/.
var $first = $('.carousel_slider a:first-child');
$first.fadeOut(function() {
$first.hide();
var $next = $first.next();
$next.fadeIn(function() {
$next.show();
$first.appendTo('.carousel_slider');
});
});
As per the jQuery docs, provide a callback to fadeOut():
.fadeOut( [duration ] [, complete ] )
If supplied, the callback is fired once the animation is complete. This can be useful for stringing different animations together in sequence. The callback is not sent any arguments, but this is set to the DOM element being animated.
Instead of writing $('thing').fadeOut().next().fadeIn() you should write:
$('thing').fadeOut(function() {
$(this).next().fadeIn()
})
This will ensure that the call to .fadeIn() does not happen until the call to .fadeOut() has completed. Also, .fadeOut() will set display: none once the opacity reaches 0, and .fadeIn() will restore display. This means that you don't actually need your calls to .hide() and .show().

Reverse onClick Event

I am a genuine javascript novice and looking some pointers in my learning - not homework nor is it anything commercial.
I have a function here which shows an element which is hidden due to the first 2 lines of the function. I start by clicking the heading and the 2 hidden divs appear, which is exactly what I wanted to happen. However, now when I use this second function, it won't return to it's windown onload state. Why is this? Is there a better way to achieve this?
1st Function
$(window).ready(function(){
$('.miniC').css("display", "none");
$('.miniI').css("display", "none");
$(".heading").click(function(){
$('.miniC').slideDown();
$('.miniI').slideDown();
$('.miniC').show();
$('.miniI').show();
});
});
2nd Function (Reverse)
$(window).ready(function(){
$(".hideOut").click(function(){
$('.miniC').slideUp();
$('.miniI').slideUp();
$('.miniC').hide();
$('.miniI').hide();
});
});
Thanks in advance and any reference to good reading material is appreciated.
* Corrected Missing closing quote - this was a mistake of me typing it into Stack Overflow - Sorry! *
It seems like you want to toggle the visibility of an element, and since you're already sliding it, why not just use slideToggle:
$(".miniC").css("display", "none");
$(".miniI").css("display", "none");
$(".heading").click(function () {
$(".miniC").slideToggle();
$(".miniI").slideToggle();
});
Example
You shouldn't need to call .hide() and .show() - they will be dealt with as part of the slide functions. However, you're calling them immediately after the slide, but that takes a while to complete (400ms by default) meaning that .hide() fires before .slideUp() completes.
Outside the question scope, but still applicable.
$('.miniC').css("display", "none");
$('.miniI').css("display", "none");
This part of the page functionality should probably in CSS, which will result in the browser rendering the initial paint of the page correctly. In your case the browser paints the "miniC" and "miniI" elements, then your jQuery code updates the CSS display property to "none" for both individually. Triggering two additional repaints of the page. So, basically with the jQuery code you are drawing the page three times for an effect that could achieved with a single paint.
Then like Charlie said add a listener for the click.
$(".heading").click(function () {
$(".miniC").slideToggle();
$(".miniI").slideToggle();
});
Because slideUp() and hide() are written inside the click event. So, it wont fire on window ready, but only onclick of $(".hideOut").
There is a typo in your first function.
a single quote is missing in the line:
$('.miniC).show();

Prevent Javascript from being executed twice

I have a script that I am developing that creates a sliding button type effect. Five div's are situated next to eachother each with a link. When one of those DIVS are clicked on the associated content is expanded and the rest of the Div's are closed.
The problem is, if a user clicks the Div twice while it loads or clicks another Div in rapid succession, cracks start to show.
I am wondering if it would be possible to only allow the query to be executed once and wait until completion rather than queuing it.
Here is my current code, if it is crap feel free to comment on how I could better it... I am not the best at Javascript/jQuery :P
function mnuClick(x){
//Reset all elements
if($('#'+x).width()!=369){
$('.menu .menu_Graphic').fadeOut(300);
$('.menu_left .menu_Graphic').fadeOut(300);
$('.menu_right .menu_Graphic').fadeOut(300);
$('.menu').animate({width: "76px"},500);
$('.menu_left').animate({width: "76px"},500);
$('.menu_right').animate({width: "76px"},500);
}
var ElementId = '#' + x;
$(ElementId).animate({
width: 369 + "px"
},500, function(){
$(ElementId + ' .menu_Graphic').fadeIn(300);
});
}
Thanks in advance,
Chris.
You need a "isRunning" flag. Check for it before you start. Set it when you start the sequence, clear it when it ends.
(function() {
var mutex = false;
function mnuClick(x){
if (!mutex) {
mutex = !mutex;
/* all code here ... */
mutex = !mutex; /* this statement should go into animation callback */
}
}
})();
mantain a state through a variable so you cannot click more than once until code has fully executed
you can unplug the onClick event handler (mnuClick) when the event starts, to effectively disable invoking the mnuClick twice, but be sure to restore it when the event ends.
Quick answer: use .addClass and .removeClass and test for the existence of the class at execution time. Test if it's set and return, or add it, execute the code, then remove it.
you can create an invisible maskin and maskout ( like the background in lightbox etc ) or disable clicks until the animation finishes.

Hide div after a few seconds

I was wondering, how in jquery am I able to hide a div after a few seconds? Like Gmail's messages for example.
I've tried my best but am unable to get it working.
This will hide the div after 1 second (1000 milliseconds).
setTimeout(function() {
$('#mydiv').fadeOut('fast');
}, 1000); // <-- time in milliseconds
#mydiv{
width: 100px;
height: 100px;
background: #000;
color: #fff;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="mydiv">myDiv</div>
If you just want to hide without fading, use hide().
You can try the .delay()
$(".formSentMsg").delay(3200).fadeOut(300);
call the div set the delay time in milliseconds and set the property you want to change, in this case I used .fadeOut() so it could be animated, but you can use .hide() as well.
http://api.jquery.com/delay/
jquery offers a variety of methods to hide the div in a timed manner that do not require setting up and later clearing or resetting interval timers or other event handlers. Here are a few examples.
Pure hide, one second delay
// hide in one second
$('#mydiv').delay(1000).hide(0);
Pure hide, no delay
// hide immediately
$('#mydiv').delay(0).hide(0);
Animated hide
// start hide in one second, take 1/2 second for animated hide effect
$('#mydiv').delay(1000).hide(500);
fade out
// start fade out in one second, take 300ms to fade
$('#mydiv').delay(1000).fadeOut(300);
Additionally, the methods can take a queue name or function as a second parameter (depending on method). Documentation for all the calls above and other related calls can be found here:
https://api.jquery.com/category/effects/
There's a really simple way to do this.
The problem is that .delay only effects animations, so what you need to do is make .hide() act like an animation by giving it a duration.
$("#whatever").delay().hide(1);
By giving it a nice short duration, it appears to be instant just like the regular .hide function.
$.fn.delay = function(time, callback){
// Empty function:
jQuery.fx.step.delay = function(){};
// Return meaningless animation, (will be added to queue)
return this.animate({delay:1}, time, callback);
}
From http://james.padolsey.com/javascript/jquery-delay-plugin/
(Allows chaining of methods)
Using the jQuery timer will also allow you to have a name associated with the timers that are attached to the object. So you could attach several timers to an object and stop any one of them.
$("#myid").oneTime(1000, "mytimer1" function() {
$("#something").hide();
}).oneTime(2000, "mytimer2" function() {
$("#somethingelse").show();
});
$("#myid").stopTime("mytimer2");
The eval function (and its relatives, Function, setTimeout, and setInterval) provide access to the JavaScript compiler. This is sometimes necessary, but in most cases it indicates the presence of extremely bad coding. The eval function is the most misused feature of JavaScript.
http://www.jslint.com/lint.html
Probably the easiest way is to use the timers plugin. http://plugins.jquery.com/project/timers and then call something like
$(this).oneTime(1000, function() {
$("#something").hide();
});
<script>
$(function() {
$(".hide-it").hide(7000);
});
</script>
<div id="hide-it">myDiv</div>
we can directly use
$('#selector').delay(5000).fadeOut('slow');

Categories

Resources