I basically want to know how global variables work in a javascript/JQuery environment. I am most familiar with a language called processing which I've been told is java-based. I expected variables in javascript and JQuery to behave like the ones in processing, but they do NOT work as I expect and I cannot for the life of me wrap my head around it.
I have a very simple example made up to illustrate my confusion:
var what="";
$(document).ready(function(){
$("p").click(function () {
what="p";
});
if(what=="p"){
alert(what);
}//end if
});//end doc ready
In processing, this would work because the 'what' variable is global and as it is changed by clicking on a paragraph, the if statement should be continuously checking to see if 'what'=='p', and trigger the alert. But that is not what happens-- 'what' only seems to be updated WITHIN the click function, even though it is a global variable, so when it comes to the if statement, 'what' still equals "" instead of "p".
If someone could explain why this happens, I will be very grateful!
The if statement only runs once when the DOM is first ready. It is not running continuously. If you want it to run during the click handler, then you would use this code:
var what="";
$(document).ready(function(){
$("p").click(function () {
what="p";
if(what=="p"){
alert(what);
}//end if
});
});//end doc ready
the if statement should be continuously checking to see if 'what'=='p', and trigger the alert.
Why? None of your code produces that functionality. If you want that to happen, you can use setInterval():
setInterval(function() {
if(what=="p") {
alert("what");
}
}, 500); // executes function every 500 milliseconds
But that is not what happens-- 'what' only seems to be updated WITHIN the click function, even though it is a global variable
No, your what variable is being updated globally. You just don't notice because you made false assumptions about the if functionality (it's only being called once).
Related
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);
I have the following JS code
$(document).ready(function(){
update_items();
adjust_size_of_menu();
});
var adjust_size_of_menu = function() {
// global boolean set in update_items_count();
if ( !items_updated )
{
alert("Treatment of update_items() not done yet");
setTimeOut( function(){ adjust_size_of_menu(); }, 1000);
}
// More treatment goes here
}
As you can see, I am setting a variable in the first function. This variable must be true before I proceed with the execution of the rest of the instructions in the second function.
The problem here is that the first time I go into adjust_size_of_menu(), it shows me the alert, which is fine. After that, it should wait 1 second then re-execute the adjust_size_of_menu() from the beginning until the item_updated boolean is true, then we continue with the rest of the code.
What is the problem with this code? I've already used the same approach elsewhere and worked just fine.
setTimeOut is not a built-in function in javascript. If you've used it elsewhere, it's because you or someone else declared it. The correct spelling is setTimeout. Note the lowercase "o".
https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
javascript is case sensitive language and it should be setTimeout()
I would like to put a delay after a button is pressed in order for the button to load the data from the cache before executing the next line of code. Would putting a sleep be the best way to do this?
Something like this or is there an alternative approach to best solve this problem?
setInterval(document.getElementById("generateButton"), 1000);
Don't use setInterval to do this. It doesn't have the functionality you seem to desire (it repeats). Instead, use jQuery and do something like this:
$("#generateButton").click(function(event){
setTimeout(function(){
//Do what the button normally does
}, 1000);
});
Or (without JQuery):
var generateButton = document.getElementById("generateButton");
generateButton.addEventListener("click", function(){
setTimeout(function(){
//Do what the button normally does
}, 1000);
});
Using setTimeout over setInterval is preferred in your case because setTimeout runs only once while setInterval runs multiple times.
I assume you have, in your html, <button id='generateButton' onclick='someFunction()'>Button Text</button>. Remove the onclick='someFunction() and put your someFunction() where I said (in the examples) "Do what the button normally does."
You can also add in the code that loads the cache a method that calls another method once the cache has been loaded (when the someFunction() from the button is called, it loads the cache, and at the end of the function (set this up using callbacks), once the cache has been loaded, it calls another method onCacheLoaded() that can be run once the cache has been loaded.
You should use callbacks, so the moment you loaded data from cache you can call it and continue executing the rest of the script.
You cannot use interval since you cannot be sure how much time is needed for the data to load. Though keep in mind the asynchronous nature of javascript and don't block the part of the script that does not depend on the data that's being loaded.
Try setTimeout:
myButton.addEventListener('click', function() {
setTimeout(delayed, 1e3); // Delay code
}, false);
function delayed() {
// Do whatever
}
Note setInterval runs a function periodically, setTimeout only once.
Also note that the delayed code must be a function (or a string which will be evaluated, but better avoid that). However, document.getElementById("generateButton") returns an html element (or null).
I need to add a Javascript event for CollapsiblePanelExtender on Javascript pageload of the page. Following is the definition of CollapsiblePanelExtender:
<cc1:CollapsiblePanelExtender ID="cpe" runat="Server" TargetControlID="pnlInstances"
BehaviorID="cpe" ImageControlID="lnkWebroleAction" ExpandedImage="~/App_Themes/Default/images/MonitorDownArrow16.png"CollapsedImage="~/App_Themes/Default/images/MonitorLeftArrow16.png"
CollapsedSize="0" Collapsed="false" ExpandControlID="lnkWebroleAction" CollapseControlID="lnkWebroleAction"
AutoCollapse="false" AutoExpand="false" ExpandDirection="Vertical" SuppressPostBack="true" />
And following is the Javascript code I am executing:
window.onload = pageLoad1();
function pageLoad1() {$find("cpe").add_expandComplete(coll_ExpandedComplete);
}
The problem is $find("cpe") returns null on this event. If I execute the same function from button click I can find the object.
Which other load events of Javascript I can use? I have tried $(documnt).ready.
You're not assigning the pageLoad1 function to window.onload, you're calling it immediately and assigning the value it returns (i.e. undefined).
You have to write:
window.onload = pageLoad1; // No parenthesis.
function pageLoad1() {
$find("cpe").add_expandComplete(coll_ExpandedComplete);
}
Or, alternatively, write a pageLoad() function, which will be called automatically by the framework when the page finishes loading:
function pageLoad() {
$find("cpe").add_expandComplete(coll_ExpandedComplete);
}
I agree with OP; there is (as original answerer pointed out) an error in the original post which is sufficient to make it look like there is not a real problem here; but I have a complex JS/Ajax driven page, and some code which tries to get some ASP.NET Ajax CollapsiblePanelExtender objects by their BehaviorID in a JS function which /is/ called on PageLoad.
These objects are usually ready, but sometimes aren't; if if try to run the code with a slight delay (100ms) they are ready. But delaying for a fixed time is not great; what event can I use, to know that these ASP.NET Ajax objects have finished building themselves?
I am having difficulties testing window.setInterval function in my Javascript file. Below is the scenario... basically I have a setInterval function in a function which I want to test:
var dummy = false; // global variable not set anywhere else
var INTERVAL_TIME = 20; // global variable not set anywhere else
function myFunction()
{
var id = window.setInterval(function() {
if (...)
{
window.clearInterval(id);
}
else
{
if(...)
{
dummy = true;
}
}
}, INTERVAL_TIME);
}
And I have the following test code in JsTestDriver:
TestMyFunction.prototype.test_myFunction() {
myFunction();
assertTrue(dummy);
}
Everytime the test executes, it fails and says dummy is false, as if the entire setInterval function was never called. I tried playing around with the interval with no success. If I put in an alert in the else clause, it popped up in a fraction of a second and disappeared (and test still fails).
The code works. I have a feeling that it is a timing issue, where the test finishes earlier than the setInterval function, hence complaining that dummy is not set to true. Any suggestions/solutions to this problem?
Thanks.
Why not put a setTimeout in your test, to delay checking for the value of dummy until after 25ms.
I used the JsUnitMockTimeout.js to simulate the setInterval function. It worked like a gem :)
assertTrue(dummy); is executed before the timeInterval of 20ms. Since you are using interval, do you perdiodically poll for the dummy value? First time poll is going to give you false unless you have a super slow PC.
It appears that "JsTestDriver cannot perform asynchronous testing". The only JS Unit testing frame work I have used with async support is Qunit.
Qunit has asyncTest which will work with ajax or timeouts.
PS: there a brand new JS Testing framework Evidence. I have not tried it.