Query about setTimeout() - javascript

Since past couple of months, I have been doing a lot of JS, but I have never really learned it in a college/from a book etc.
Here is a question:
$scope.selectTab = function($index, tab) {
$scope.template = $scope.templates[$index];
$scope.data.tabSelected = tab;
setTimeout(function() {
console.clear();
console.log($scope.template);
console.log(document.getElementById("SomeDiv"))
console.log("Going to draw now...")
draw_analytics($scope); // Draw on SomeDiv
}, 0);
}
while the above code works; but the below one doesn't.
$scope.selectTab = function($index, tab) {
$scope.template = $scope.templates[$index];
$scope.data.tabSelected = tab;
console.clear();
console.log($scope.template);
console.log(document.getElementById("SomeDiv"))
console.log("Going to draw now...")
draw_analytics($scope);
}
I am using AngularJS for some tabbing thing, but that is irrelevant I guess.
In the top code, when I try to get SomeDiv dom, I actually get it's HTML content, while in the bottom code, null is returned.

When you use settimeout with an anonymous function, it doesn't execute it right away. It adds it to a queue to be executed after the current events finish.
This is opposed to running it without settimeout, which just executes it immediately.
If I had to guess, "SomeDiv" is being created or manipulated with the tab change. So running the code right away may cause a situation where the code executes before the div is actually created. While calling "settimeout" will wait until the current events complete before executing. Although it looks like it's inline with the event, it's really just scheduling the anonymous function to run at the end.
I created a fiddle to illustrate what I'm talking about.
http://jsfiddle.net/pS54r/
The first button using settimeout, the second button doesn't.
$('#clickme').click(function () {
WriteToDiv('First Button 1');
setTimeout(function () {
WriteToDiv('First Button 2');
}, 0);
WriteToDiv('First Button 3');
});
$('#clickme2').click(function () {
WriteToDiv('Second Button 1');
WriteToDiv('Second Button 2');
WriteToDiv('Second Button 3');
});

Related

Baffled by loops - any help welcome

I’m struggling with making Javascript repeat this code block. It's for a code-operated Phidget switch and works just the once to turn an electronic relay on and off (with a timer for duration) ("Phidget22" is the Node package specific to the device).
I can't find a working method to make the process repeat itself.
Below is the working code, with explanatory notes for what the stages do.
var phidget22 = require('phidget22');
function runExample() {
//Create your Phidget channels
var digitalOutput0 = new phidget22.DigitalOutput();
//Set addressing parameters to specify which channel to open (if any)
digitalOutput0.setHubPort(2);
digitalOutput0.setDeviceSerialNumber(606877);
//Assign any event handlers you need before calling open so that no events are missed.
//Open your Phidgets and wait for attachment
digitalOutput0.open(5000).then(function() {
//Do stuff with your Phidgets here or in your event handlers.
digitalOutput0.setDutyCycle(1);
setTimeout(function () {
//Close your Phidgets once the program is done.
digitalOutput0.close();
process.exit(0);
}, 3000);
});
}
Not sure if I get the idea, but perhaps setInterval would work for you.

How to use Ajax to populate externally loaded div (jQuery)

I am creating tests for a page and HAVE to use jQuery to change elements on the control version of the page for each different experience.
I'm using jquery to load an element from an external page and replace a div. However, on the external page, it uses an ajax call to an api to populate the div, so I copied over the function with the ajax call.
I think it is attempting to make the ajax call before the new div is actually loaded on the page.
I've tried moving the function, wrapping the load function within the ajax call, but it still doesnt work.
I could be missing something obvious, but here's that part of my code:
$('.replace-div').load('external.html #replace-div');
function waitForLoad() {
if ($('#replace-div')) {
var object;
$.ajax({
url: "https://api.com",
async: false,
success: function(result) {
object = result;
var variable1 = object["blah"][0].value,
var variable2 = object["blah"][0].value,
var variable3 = object["blah"][0].value,
var variable4 = object["blah"][0].value,
$('newElement').attr('href', variable1);
$('newElement2').attr('src', variable2);
$('newElement3').attr('href', variable3);
$('newElement4').text("text" + variable4 + "more text");
}
});
} else {
setTimeout(waitForLoad, 15);
}
}
waitForLoad();
I don't get any errors in the console, and when I paste the above waitForLoad function into the console, it populates totally fine. obviously this is after the page loads the new div, so i just need to know how to make the ajax call wait for the load.
I've tried .ajaxComplete(), but it doesnt help.
$(function() {}); also does not work
.load() has a callback argument where you supply a function to run after the data is loaded.
$('replace-div').load('external.html #replace-div', function() {
$.ajax(...);
});
So, what happens is that, once waitForLoad is called for the first time, it doesn't see the div loaded, the code goes to the else block and executes again with a 15ms timeout. 15ms is not enough for the div to load, most likely.
You can try three things (ordered from worse to better):
Try increasing the timeout to a bigger number. Start with 1000 (1000ms - 1 second) and see if it works or you need to increase it. It's more likely you'll have to decrease it
Try using setInterval instead of setTimeout, which will repeat itself. Of course, once it loads, you'll need to clear the interval so it stops. Also, better use bigger timeouts/intervals, like 50 or 100ms b/c the fast firing timers can slow down a page a lot
E.g.
$('.replace-div').load('external.html #replace-div');
function waitForLoad() {
if ($('#replace-div')) {
clearInterval(window.waiter);
...
} else {
window.timer = setInterval(waitForLoad, 50);
}
}
waitForLoad();
Same as 2, but using more idiomatic callback function after load call.
// the window.waiter is the interval handle, and it will run every 100ms. It calls .load every time, and if the #replace-div is found, unsets the interval handle.
window.waiter = setInterval(function() {
$(".replace-div").load("external.html #replace-div", function() {
if ($(".replace-div #replace-div").length) {
// found the DIV
// code...
clearInterval(window.waiter); // bye interval handle, thanks
}
});
}, 100);

How do I add a load icon to a page that just processes javascript code?

I use Ajax load icons all the time for when I do ajax requests.
I want to know if it's possible to accomplish the same thing with just regular javascript code. For example:
$('button').on('click', function(){
showLoadingBar();
longProcess();
hideLoadingBar();
});
longProcess() is just a function that can take 1-3 seconds to process (it does a lot of calculations and manipulates the DOM but doesn't do any ajax requests).
Right now, the browser halts/freezes during these 1-3 seconds, so what I would rather do is show a loading icon during this time. Is this possible? The code I have above pretty much ignores showLoadingBar().
The DOM won't be updated until the current Javascript process ends, so you can't do it just like that. You can however use setTimeout to get around that:
showLoadingBar();
setTimeout(function() {longProcess(); hideLoadingBar(); }, 1);
What happens above, in case it isn't clear, is that showLoadingBar is executed, then a timeout is set up. The current process will then end and allow the DOM to update with the loading bar, before the timeout is invoked, very shortly after. The handler executes your heavy function and when it's done, hides the loading bar again.
The following will give you control over the action on click. What this means is you can disable the clicking ability till it has finished running. But also i've including setTimeout which returns control to the browser (thus removing that annoying "lockup" feeling) and in the timeout function we preform our long process then re-enable the button! VIOLA!
function startProc() {
var $this = $(this);
$this.off("click", startProc);
showLoadingBar();
setTimeout(function() {
longProcess();
hideLoadingBar();
$('button').on('click', startProc);
});
}
$('button').on('click', startProc);
Dude,
Use the .bind method, which in this case is performed so:
$('button').bind('click', function(){
showLoadingBar();
longProcess();
hideLoadingBar();
});

Show a message box which slides out, delays for 3 seconds and slides in with Mootools?

I'm creating a error message displaying box which slides out, delays for 3 seconds and then slides in with Mootools. This is what I'm currently doing now, how can I correct it to get it work for me?
var slide = new Fx.Slide($("error"));
slide.slideOut('horizontal').chain(function(){
$("error").set("text", message);
}).chain(function(){
this.slideIn('horizontal').delay(3000);
}).chain(function(){
this.slideOut('horizontal');
});
You basically have your mootools correct, but are missing a few key items that would make your script function properly. I have pasted a working version below, and then made some comments:
var slide = new Fx.Slide($("error"));
slide.slideOut('horizontal').chain(function () {
$('error').set('text', message); this.callChain(); //NOTE
}).chain(function () {
this.slideIn('horizontal');
}).chain(function () {
this.slideOut.delay(3000, this, 'horizontal'); //NOTE
});
Notice the this.callChain() on the
3rd line. Not having this was what
was stopping you seeing anything.
The Fx class uses the callChain()
method internally to start the next
step in the sequence, but if your
argument to chain() doesn't contain
one of Fx's methods, callChain() is
not called, so you have to do it
manually.
Your call to delay was in the wrong place. Delay() delays the execution of the function it is applied to, it does not insert a pause into a chain. Therefore to display the error message for 3sec you need to add delay to the the last function call, because this is the one you want to slow down
Your call to delay was incorrect. Delay applies to the function, not the return value of the function, hence Dimitar's suggestion above. Have a look at function in the mootools core documentation for more info
By the sounds of it, you do not have firebug installed. This would have let you explore the DOM to find that your code changes the margins and then the text, but nothing happens after that. Firebug is super useful, so install it ASAP
My solution (mootools 1.3) is below, and basically relfects what dimitar was suggesting:
$('error').set('slide', {
mode: 'horizontal'
}).get('slide').slideOut().chain(function () {
$('error').set('text', message); this.slideIn();
}, function () {
this.slideOut.delay(3000, this);
});
Hope it helps

jQuery queue messages

I've got a short function that should show messages on a website.
function showHint() {
$('#notify').html('message text').show('slide', {direction: 'right'}, 500);
}
And there is another function that hides the messages.
function hideHint() {
$('#notify').hide('slide', {direction: 'right'}, 500);
}
The Problem is that if I call this function more than one times it tries to show all messages at the same time and everything breaks. I want to call the function twice and then it should queue the animations and show one message after another. The function should be called more than one times at the same time but shown one after another. The next message should be shown when the firs hides.
How could I solve the Problem? Would be nice!
Here's a mini custom plugin that I've used in the past that chains a bunch of animations one after another.
// Good for serializing animations
$.fn.chain = function(fn) {
var elements = this;
var i = 0;
function nextAction() {
if (elements.eq(i)) fn.apply(elements.eq(i), [nextAction]);
i++;
}
nextAction();
};
You might call it like so (Here's an example of it in use):
$(document).ready(function() {
$('li').chain(function(nextChain) { this.slideToggle("fast", nextChain); });
});
The function you pass to chain passes another function that you must call when you're down with one cycle. In the example above, we just pass the nextChain function as the callback to the slideToggle.
Your showhint function could just start by hiding the notification and when that is complete the callback would be what is the existing showhint function, that would change the text and show it. Code shouldn't be difficult given what you've already done.
can you not just use a notification plugin? here are two (one, two) that are pretty spiffy.

Categories

Resources