Using setInterval in JavaScript without using an inline, anonymous function - javascript

What I'm trying to achieve is that initially data will be loaded and then be updated every ten minutes using the same function.
Consider this code:
var updateNamespace = (function() {
var object = '#updates',
load = 'loader';
return {
update: function() {
$(object).addClass(load).load('update.php', function(reponse, status, xhr) {
if (status == 'error') {
$(this).html('<li>Sorry but there was an error in loading the news & updates.</li>');
}
$(this).removeClass(load);
});
}
}
})();
setInterval(updateNamespace.update(), 600000);
I get this error:
useless setInterval call (missing quotes around argument?)
How can I fix this?
What's a better and more elegant way of writing this or using the setInterval function?
Thanks.

You need to use:
setInterval(updateNamespace.update, 600000);
(Note the removed invocation() operator.)
Your code, as written, will actually invoke updateNamespace.update when you call setInterval. Hence,
setInterval(updateNamespace.update(), 600000);
evaluates to
setInterval(undefined, 600000);
You want to pass setInterval a REFERENCE to your function, not the result of its invocation.

For some reason JavaScript wants to see quotes around the method your calling. As if it was a string. Not sure why it works like that. Matt H. said if you pass a reference that will fix the problem. But it won't work if you need to pass in an argument. So I don't know maybe JavaScript just saves the method as a string and then coverts to back to normal when it's used.

try setInterval('updateNamespace.update()', 600000);
Note the quotes around the function call

Related

JS / Jquery .load and .length

I'm new to Jquery/javascript with almost all of my experience being in PHP. I am now finding the importance of how things are ordered :)
So I'm trying to load some <div>s into the container #text-container using .load and then count them. My understanding of jquery's load function is that the 2nd argument is a callback function which will only run once all data has been loaded. But it is always reported as 0 even if there are 4-5 divs being placed in the container. Am I missing something?
1.txt
<div>1</div><div>2</div>
Code:
$("#text-container").load("1.txt",alert($("#text-container div").length));
This is just an example but I need to use that number to do a whole bunch of maths in other functions. So if I call those instead of alert and try to run .length in there they all get 0 and my math doesn't work :(
Ideas?
You need an anonymous function for the callback
$("#text-container").load("1.txt", function(data) {
alert( $("#text-container div").length )
});
This is just an example but I need to use that number to do a whole
bunch of maths in other functions.
Note that it's async, so you can't use it until it's actually there, and why would your .txt file contain DIV elements, seems like the wrong file extension to me ?
Answer
$("#text-container").load('1.txt',function(){
alert($("#text-container div").length);
});
Explaination
First let us talk about the callback function passing, the right syntax:
$(selector).load(source,callback);
Suppose you have some function named as gg and we want to use it in place of callback
function gg(){
//some code for task 1
}
now lets use it as callback
(the wrong way)
$(selector).load(source,gg());
Note: when you write the function with parenthesis (), the function is called at the same time, so you just need to pass the identifier
(the right way)
$(selector).load(source,gg);
OR USE ANONYMOUS FUNCTION
$(selector).load(source,function(){
// some code for task 1
});
Note: Instead of defining a function only for callback and if you are not using it again it is preferred to use anonymous function
You are not doing what you think you do. You pass the result of alert() as an argument.
$("#text-container").load("1.txt",alert($("#text-container div").length));
is equivalent to :
var data = alert($("#text-container div").length); // data = 0
$("#text-container").load("1.txt", data);
What you want is to pass a function as an argument :
var callback = function() {
alert($("#text-container div").length);
}
$("#text-container").load("1.txt", callback);
or shorter :
$("#text-container").load("1.txt", function() {
alert($("#text-container div").length);
}

Javascript error halts $document.ready()

I'm updating an existing website running on Expression Engine. So far, I've stayed away from any code I didn't write or couldn't understand. I recently must have altered some bit of code someplace (helpful, I know) and now a block of JS I didn't write is causing an error that seems to bypass the document.ready() event. The window.load() event however is still taking place.
In the Chrome DevTools Console, the error "Uncought TypeError: Cannot call method 'replace' of UNDEFINED" points to the definition of a function "fixedEncodeURIComponent" pasted below.
$("#MessageContainer.Counted").counter({
type: 'char',
goal: 250,
count: 'down'
}).change(function(){
var TEMP = fixedEncodeURIComponent($(this).val());
$("#Message").val(TEMP);
});
var TEMP = fixedEncodeURIComponent($("#MessageContainer.Test").val());
$("#Message").val(TEMP);
function fixedEncodeURIComponent (str) {
str=str.replace(/"/g, '');
return encodeURIComponent(str).replace(/[!'()*]/g, escape);
}
As I interpret the error, this function is being passed a variable that is not a string. I added an alert(str) to the function definition and the result was UNDEFINED as I expected. The first of several unknowns for me is which call to the function 'fixedEncodeURIComponent' is being passed a bad variable. I assume that it's the first call, but that's just a guess. It so happens that this first call contains a syntax I have never encountered before. I don't know how to interpret what happens when $(this) is passed as a function argument.
Any insights would be greatly appreciated. Also, if there's more information you need please let me know. The client's site is password protected but I can include any code you request.
Thank you.
I'm taking a guess that the }); on line 3 is exiting a document.ready context. If that's the case then your second call to fixedEncodeURIComponent may be getting called before the DOM is even loaded.
Start by wrapping
var TEMP = fixedEncodeURIComponent($("#MessageContainer.Test").val());
$("#Message").val(TEMP);
in a
$(function() {
// code
});
block. If that doesn't work, check that #MessageContainer.Test actually matches an element. Since this is code you inherited, the class name "Test" clues me in that the block in question might be a remnant of someone trying to debug an issue and maybe it should have been removed.
I suspect $("#MessageContainer.Test") since it looks like its supposed to be an ID selector instead of what it actually is when jQUery parses it(which is an ID selector combined with a class selector). $("MessageContainer\\.Test") allows you to select an element with ID MessageContainer.Test

Pass Hash from URL to a Function with Delay

I am trying to pass a has such as http://mysite.com/#32132 via JS to a custom function.
Here's the function:
var downloadVideo = function(passed){
console.log(passed);
}
And here's how I'm getting and passing the hash from the URL:
if(window.location.hash){
var hash = window.location.hash;
hash = hash.substring(1, hash.length); // Remove the # from the hash
setTimeout('downloadVideo('+hash+')', 3000)
}
After 3 seconds, I just get an error in the console:
Uncaught ReferenceError: 32132 is not defined
I've tried different ways of calling downloadVideo. With quotes, without quotes, without the plus signs. Nothing seems to work. If I console.log the hash var immediately before the setTimeout it displays it correctly.
You need to represent it as a string if there's anything more than just numeric characters...
// ------------------v--------v
setTimeout('downloadVideo("'+hash+'")', 3000);
But better to pass a function that closes over hash...
setTimeout(function() { downloadVideo(hash) }, 3000);
You can use a closure to do that:
setTimeout(function() {
downloadVideo(hash);
}, 3000);
1) You don't need the second argument in your has substring - if omitted, the substring matches to the end of the string
2) with timeouts it's better to use anonymous functions; evaluated strings are, well, evaluated. Generally a bad idea.
3) the error is coming because you're passing a string without quotes. Fixing point 2 to use an anonymous function would make this error both more visible and harder to commit in the first place
4) you could always apply the timeout in the function, rather than in the call to it
Anyway:
setTimeout(function() { downloadVideo(hash); }, 3000);
Assume that the value of hash is test then:
'downloadVideo('+hash+')'
...evaluates to:
downloadVideo(test)
Notice that there are no quotes around the string test so it's treated as though it refers to a variable (that doesn't exist). This is one of many reasons not to pass strings to setTimeout. It's a bad practice, as described here:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/eval#Don%27t_use_eval!
It's far better to pass a function to setTimeout. It's safer, easier to read, and doesn't suffer from the problem you've see here. When no arguments are required, simply refer to the function by name:
setTimeout(downloadVideo, 3000)
If arguments are required, as they are in your case, then you'll need to pass a reference to an anonymous function and have that function call the function that you want to invoke:
setTimeout(function() {
downloadVideo(hash);
}, 3000)

How to make Javascript timer work for variable parameter

The Javascript timer event has this basic syntax:
var t=setTimeout("javascript statement",milliseconds);
I have this function that gets called onkeyup() for some text box. I want the numeric_value_search() function to be called after a certain amount of time, which is 5 seconds in this example.
The key line is the 5th line. I have four different ways that it might be written, each of which gives the specified error:
timer=setTimeout(numeric_value_search(boundBox),5000);
ERROR: useless setTimeout call (missing quotes around argument?)
timer=setTimeout("numeric_value_search(boundBox)",5000);
ERROR: boundBox is not defined
timer=setTimeout("numeric_value_search("+boundBox+")",5000);
ERROR: missing ] after element list
timer=setTimeout(numeric_value_search("+boundBox),5000);
ERROR: data is passed nicely and there are no explicit errors but the timer doesn't work
var timer;
function chk_me(boundBox){
console.info(boundBox.id);
clearTimeout(timer);
// --- timer code here --- e.g. timer=setTimeout("numeric_value_search("+boundBox+")",5000);
}
As #kgiannakakis already said,
setTimeout(function() {
numeric_value_search(boundBox);
}, 5000);
is the way to go.
The reason is simple: When using a string argument it's like using eval() which is usually evil. When passing a function however you not only avoid putting code inside a string (which breaks syntax highlighting and might require escape orgies) but also have the possibility of using a closure to access variables in the current context without embedding them into a string (which might lead to code injection if not done properly).
Try this:
setTimeout(function() {
numeric_value_search(boundBox);
}, 5000);

Firefox Javascript Events Anonymous Function

I'm attempting to register an anonymous function when a user clicks a cell in an HTML table. Here's some of the raw, unadulterated code:
document.getElementById(
"course"+displayed_year_index+occurrences_indices[displayed_year_index]).onclick =
eval("function() {PrintReceipt("+result.years[result_year_index].rul_code+");};");
Note the use of eval, since this sits in a loop and the anonymous function is different each time round.
Suffice to say, this works absolutely fine in Firefox 2. But, Firefox 3 throws a 'Syntax Error', pointing inside the brackets after the word 'function'.
Does anybody have any smart ideas on how I can fix this?
Just to make it crystal clear what I'm attempting to do, here's a much simplified example:
for (index=0; index<4; index++) {
document.getElementById("div"+index).onclick =
eval("function () {Foo(index);};");
}
In other words, I wish to trigger the same function with a different parameter value for each div.
Have you tried something like this?
document.getElementById('course' + displayed_year_index + occurences_indices[displayed_year_index]) =
function (nr)
{
return function () { PrintReceipt(nr) }
} (result.years[result_year_index].rul_code);
Can you please post the loop to help us find the problem instead of making us guess what you're trying to do?
IMHO closures should not be used in this case and there is no need to create a new function for each onlick (uses much more memory than necessary) and eval is the wrong answer.
You know that the element you are getting with getElementById is an object and that you can assign values to it?
for ( /* your definition */ ) {
var e = document.getElementById(
"course"+displayed_year_index+occurrences_indices[displayed_year_index]
);
e.rul_code = result.years[result_year_index].rul_code;
e.onclick = PrintReceipt;
}
But you should define the PrintReceipt first:
function PrintReceipt() {
//This function is called as an onclick handler, and "this" is a reference to the element that was clicked.
if (this.rul_code === undefined) { return; }
//Do what you want with this.rul_code
alert (this.rul_code);
}
Use closures like Tom suggested.
Heres a good explanation by John Resig: How Closures Work (pdf)
It seems like this is the direction that you would want to go:
document.getElementById("course"+displayed_year_index+occurrences_indices[displayed_year_index]).addeventlistener("click", function() {
var current_rul_code = result.years[result_year_index].rul_code;
PrintReceipt(current_rul_code);
}, true);
This should cause each to onclick event to be created within a different scope (each iteration of the loop). Closures will take care of the rest.

Categories