Unable to get setTimeout to work in javascript - javascript

I am using jquery to slide up an down a div.
For some reason setTimeout is not working (looks like a function scope issue).
Not able to figure out what is wrong with the below code.
(both functions are inside $(document).ready(function(){ } )
$('.slider-thumb').click(function(){
var source = $(this).attr("src");
$('#image_view').css('background-image',"url("+source+")");
$('#image_view').slideDown(1000, calbck);
initiate_timeout();
function calbck(){}
});
function initiate_timeout(){
var time_out = setTimeout(function() {
$('#image_view').slideUp(1000, calbck);
},2000);
}

Indenting the source code shows that you indeed have some scoping issue. The calbck function is private to the click handler function, and is thus not visible to initiate_timeout function. Either make calbck a top-level function, or make initiate_timeout a function local to the click handler function.
$('.slider-thumb').click(function() {
var source = $(this).attr("src");
$('#image_view').css('background-image',"url("+source+")");
$('#image_view').slideDown(1000, calbck);
initiate_timeout();
function calbck(){}
});
function initiate_timeout(){
var time_out = setTimeout(function() {
$('#image_view').slideUp(1000, calbck);
}, 2000);
}

You have some JS errors and scoping issues. Why would you ever have debugging turned off when trying to troubleshoot an error? Change your code to this:
$('.slider-thumb').click(function(){
var source = $(this).attr("src");
$('#image_view').css('background-image',"url("+source+")");
$('#image_view').slideDown(1000);
setTimeout(function() {
$('#image_view').slideUp(1000);
},2000); // will start 2 seconds after slideDown starts (which is 1 second after it completes)
});
or even better, use the completion function of the first animation to set the timer:
$('.slider-thumb').click(function(){
var source = $(this).attr("src");
$('#image_view').css('background-image',"url("+source+")");
$('#image_view').slideDown(1000, setTimeout(function() {
$('#image_view').slideUp(1000);
},1000)); // will stay open for 1 second before sliding up again
});
Or, even better, using jQuery's delay/queuing, you can do this:
$('.slider-thumb').click(function(){
var source = $(this).attr("src");
$('#image_view').css('background-image',"url("+source+")");
$('#image_view').slideDown(1000).delay(1000).slideUp(1000); // delay 1 sec between effects
});
The calbck you were trying to pass to slideUp was not defined in the scope you were using it (inside of initiate_timout()). It was private to your click handler.
jQuery probably has better ways to chain effects than using your own timer, but I see no reason why this code shouldn't work if it matches your HTML.
Note: if your background image wasn't already pre-cached, it may not be loaded right away when your slideDown starts.

Are you getting any errors? You're passing an undefined value as calbck to slideUp in the setTimeout function.
It works for me (with my modified organization): http://jsfiddle.net/v3cjG/1/
And when I run your exact code ( http://jsfiddle.net/v3cjG/2/ ) I get an error for "Can't find variable calbck"--the var I said you were passing without defining.

Related

stopping a nested javascript function running more than once

I'm trying to get a javascript function to run only once. I've seen this question has been asked before, e.g. Function in javascript that can be called only once, but I can't get the solutions in here to work. I'm not sure if it's because I've got nested functions, or whether there's something I'm missing. Essentially, I'm trying to run a function which, when a webpage is scrolled, it:
- runs a little animation on a canvas in the header
- reduces the size of the header
- leaves it at that
But when there is any subsequent scrolling, the animation keeps re-running. Here's a summarised version of the non-working code:
$(document).on("scroll",function(){
var arrange_title = function(){
//some code
};
if($(document).scrollTop()>0){
arrange_title();
arrange_title = function(){};
setTimeout(function(){
$("header").removeClass("large").addClass("small");
},1000);
}
});
I've also tried declaring a global variable, setting it to "false" in a "window.onload" function, then set it to true in an if function that runs the animation (the if function running only if the variable is false), but that doesn't stop it either. Thoughts?
What you're looking for is something along the lines of listenToOnce where the listener fires the one time, but never again. This could be modified to a number of calls, but the logic is like so:
Register the listener.
Then once the listener fires, remove it.
See .off
$(document).on("scroll",function(){
var arrange_title = function(){
//some code
};
if($(document).scrollTop()>0){
arrange_title();
arrange_title = function(){};
setTimeout(function(){
$("header").removeClass("large").addClass("small");
// $(document).off('scroll'); // or here
},1000);
}
$(document).off('scroll'); // remove listener, you can place this in the setTimeout if you wish to make sure that the classes are added/removed
});
Don't use a time out. That is why you are getting in trouble. Declare a variable outside of your function using var, that will make it global. Your code should be inside of a check for that variable. Before executing your code the first time but inside of the check, change that variable so that the code will never run again.
Try avoid setTimeout. Almost all animation can be watched for end.
function doHeaderAnimation() {
return $('header').animate();
}
function makeHeaderSmall() {
$("header").removeClass("large").addClass("small");
}
function handleScroll(event) {
if ($(document).scrollTop() > 0) {
doHeaderAnimation().then(makeHeaderSmall);
$(document).off("scroll", handleScroll);
}
}
$(document).on("scroll", handleScroll);

Trouble with setTimeout with addEventListener

I have a vimeo video that I want to play 3 seconds after a button is clicked. I can get the video to play on click, but I can't seem to get the setTimeout in the right spot... any suggestions?
var iframe1 = document.getElementById("prelearn-1");
var player1 = $f(iframe1);
var prelearnBtn = document.getElementById("prelearn-1-btn");
prelearnBtn.addEventListener("click", setTimeout(function(){player1.api("play")}, 3000));
I'm using the vimeo froogaloop API.
Just wrap it inside a function -
prelearnBtn.addEventListener("click", function(){
setTimeout(function(){
player1.api("play");
}, 3000);
});
The setTimeout function takes in a callback function. Just wrap your code in an anonymous function, then it should work. Also, you might have cross-domain issues if you're attempting to access the contents of an iFrame.
var iframe1 = document.getElementById("prelearn-1");
var player1 = $f(iframe1);
var prelearnBtn = document.getElementById("prelearn-1-btn");
prelearnBtn.addEventListener("click", function(){setTimeout(function(){player1.api("play")}, 3000)});
AddEventlistener takes anonymous function as the second argument. So you need to wrap the setTimeout inside the anonymous function. Whenever the click event happens, the setTimeout code will trigger and will play the video.
prelearnBtn.addEventListener("click", function () {
setTimeout(function () {
player1.api("play")
}, 3000)
}, false);
ES2015 shorter syntax + utilizing the 3rd argument of the setTimeout will make our code shorter and nicer while keeping it readiable:
document.querySelector('button').addEventListener("click",() =>
setTimeout(console.log, 1000, "play")
)
<button>Play</button>
The above example replaced OP's player1.api method with console.log for the sake of printing the argument, which illustrate the code works.

Calling functions from within another - javascript

I'm relatively new to javascript and having a couple of issues that I'm hoping you can help with. I'm utilizing the fabric library with canvas to create an animation of sorts.
I have a function that is called when the relevant button is pressed:
//for starting the animation
startSim.onclick = function(){
//obtain speed value from the control panel.
var speed = 10000 / (new Number(speedControl.value));
//stuff
//animation process
object.animate('top', '+='+canvas.height,{
duration: speed,
abort: function(){
var returnedBool;
//Pause is pressed, simulation pauses
if(pause){
//stuff
}
//restart required
if(restart){
//stuff
}
//option here to save data?
return returnedBool;
},//end abort callback
onChange: canvas.renderAll.bind(canvas),
onComplete: function(){
//stuff
}
});//end animate callback
};
What I'd like to do is call certain other functions while the above animation is active.
I know how I'd like to do this using Java or C++ but I can't seem to call the function.
I have a display panel that should output various information - as the animation completes variables will change and I'd like them to be output on the screen and be updated as they change.
I'm testing with a simple function:
function updateInfoPanel(testSpeed){
var test = document.getElementById('currentSpeed');
test.innerHTML = test.innerHTML + testSpeed;
}
I think I need to call this in the main animate loop, if I call it before it's fine but obviously only displays the variable once. Could someone tell me where I'm going wrong please?
I also have a basic collision detection function that works but not within the animate loop and I think these problems are linked.
Many thanks for any help.
I removed the unnecessary parts of the code to save space.
So I've just tried to use a function as the result of onChange:
onChange: function(){
canvas.renderAll.bind(canvas);
updateInfoPanel(speed);
},
This doesn't present syntax errors but the animation no lingers runs although the speed variable does update in the info panel very quickly. :(
You need to call renderAll(), bind is actually returning a function to be used as a handler. Just try this code:
onChange: function(){
canvas.renderAll();//.bind(canvas);
updateInfoPanel(speed);
},
And let me know if it helped?

jQuery .load(function) synchronous

What is the best way to use the jQuery load function synchronously.
I need to load an image but can't execute the next line of code until that image has loaded.
I could loop a variable until the load has completed but was wondering if there was a better way of doing that.
var img = jQuery('<img src="' + url + '"/>').load(function () {
});
//Run code here once img load has comlpeted.
You can also use CallBack function to get Synchronous Behaviour -
var result = $('#main-container').load( 'html/Welcomeform.html',
function () {
if($("textarea").find("#mail-id")){
$("textarea#mail-id").val(email_id);
}
} );
From what I know, the load event will always fire asynchronously, except if the image is already cached (in some browsers). The only reliable solution is to put the code in a callback like you did. However, to make sure the load handler will always be fired in all browsers, even if the image is cached, make sure to add the handler before setting the src property of the image.
var img = jQuery('<img src="' + url + '"/>').load(runner);
function runner() {
//run code here once image is loaded
}
I arrived here looking for a similar solution. From the reads, it is not possible with .load, you need to use an AJAX request, as the question comment points out.
In my case I need to load a html file and I have added a transition to change the content. The old content were showed before the new one after the transition even if I was showing the content inside the load callback.
var main = $("#main");
main.load("about.html", displaySection);
function displaySection () {
main.show('blind');
}
My workaround has been to run the transition that shows the loaded content inside a timeout function with a of 200 for the delay parameter.
var main = $("#main");
main.load("about.html", displaySection);
function displaySection () {
setTimeout(function() {
main.show('blind');
}, 200);
}
The problem could be if the connection is so slow that the new page takes more than 200 ms to load, but in this case I wonder the callback will be launched later on. I don't understand why is not working without the timeout that I feel quite ugly, but it solved my problem ... just in case any other has not given a thought on this possibility.
The callback function in load() will fire once the basic elements of the screen have been retrieved, (the actual html) but doesn't wait for images to finish, you can use this to make it wait.
$('#holder').load(function() {
var imgcount = $('#holder img').length;
$('#holder img').load(function(){
imgcount--;
if (imgcount == 0) {
/* now they're all loaded, let's display them! */
}
});
});

jQuery execute code each time element has class

I'm trying to execute a piece of code each time a specific element has a certain class in jQuery.
The problem I'm experiencing is that the code only executes once, then seems unactive. I'm using an if statement, but I also tried while. When I tried while the nothing really worked so that wasn't a good idea. Is there any solution? Here's the code:
if($(".slide:first").hasClass("active-slide")) {
$(".prev").hide();
$(".next").click (function () {
$(".prev").show();
});
}
JQuery queries are performed only once. You could execute it in an interval:
var checkPage = function(){
if($(".slide:first").hasClass("active-slide")) {
$(".prev").hide();
$(".next").click (function () {
$(".prev").show();
});
}
}
var intrvl = setInterval( checkPage, 300 );
This might work, but it could become really slow on big pages.
I'd rather attach the checkPage() function to the slide change event.
Wrap it in a each(), so that it executes every time slider:first occurs.
$(".slide:first-child").each(function(){
// your function goes here
});
EDIT: :first only targets the first instance of it on the page, so it will only fire one time anyway. You are probably looking for :first-child.

Categories