How to make Javascript timer work for variable parameter - javascript

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);

Related

JavaScript setTimeout infinite loop without recursion

I cannot use Obfuscator.io to uglify my JS script because it contains a setTimeout within a function that calls itself.
MCVE:
function repeater() {
// DO SOME STUFF...
setTimeout(repeater, 100);
}
repeater();
Custom obfuscation settings required to reproduce:
- Identifier Names Generator: Mangled
- Reserved Names: $ - jQuery
Obfuscator.io's error message:
Error: #postConstruct error in class t: #postConstruct error in class t: Maximum call stack size exceeded
I've read a few other Stack Overflow questions about this. I understand that calling setTimeout(func) inside func is not actually recursion.
But still, Obfuscator.io's algorithm can't handle a self-invoking setTimeout delay.
How do I make a repeatedly-executing function using setTimeout without calling it in the function itself? I don't want to use setInterval because I want the delay to begin each time after the function's code has run. setInterval ignores that.
I think your issue is actually in the use of
Reserved Names: $ - jQuery
as using that as the configuration results in this
Which is what you're getting, if you change it to ^$ which is what the text box and description on the website says it should be, your code obfuscates fine
Reserved Names
Disables obfuscation and generation of identifiers, which being matched by passed RegExp patterns.
For instance, if you add ^someName, the obfuscator will ensure that all variables, function names and function arguments that starts with someName will not get mangled.
I this you have something like that:
function repeater() {
// DO SOME STUFF...
const someCodeInJQuery = $('#someId')
setTimeout(repeater, 100);
}
repeater();
Just need change to:
function repeater() {
// DO SOME STUFF...
const someCodeInJQuery = jQuery('#someId'); // Pay attention here
setTimeout(repeater, 100);
}
repeater();
Anwer: change $ to jQuery in your code, because obfuscator have
reserved words
Reccomendation: the best way - use uglifyJS instead of obfuscator

JavaScript webkit syntax error, work fine in Firefox; value vs. reference

I'm going through a collection of DOM elements, and when criteria is found, DOM element gets a CSS class flashMe added to it.
CSS is a 1 second animation - I'm then using a setTimeout to remove the CSS class 1.5 seconds later.
If I use function (varCounter) in the loop, it will use varCounter reference, not value.
So I'm using function (passedIndex = varCounter) which passes a current value, and works great in Firefox.
In WebKit (Chrome & Safari) same code throws: SyntaxError: Expected token ')' on 6th line: function(pIndex=b)
var self=this;
for(var b=0;b<this.someDOMcollection.length;b++){
if(this.someDOMcollection[b].id==someCriteria){
this.someDOMcollection[b].classList.add('flashMe');
setTimeout(
function(pIndex=b){
self.someDOMcollection[pIndex].classList.remove('flashMe');
}
,1500);//end Timeout
break;
}//if
}//b
One way to get around it is to make a separate function, and pass it currently found index value, but ideally I would like to keep it within the same block.
Any help or pointers would be greatly appreciated.
Default values is an ES6 extension and is currently only supported by Firefox.
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/default_parameters
The simple solution here would be to store the value in a closure :
var self=this;
for(var b=0;b<this.someDOMcollection.length;b++){
(function(pIndex){
if(this.someDOMcollection[b].id==someCriteria){
this.someDOMcollection[b].classList.add('flashMe');
setTimeout(
function(){
self.someDOMcollection[pIndex].classList.remove('flashMe');
}
,1500);//end Timeout
break;
}//if
})(b);
}//b
function(pIndex=b){ is not valid JavaScript (yet). Use a Immediately-Invoked Function Expression (IIFE), instead:
(function(pIndex){ // Accept a parameter, named `pIndex`.
setTimeout(function(){
self.someDOMcollection[pIndex].classList.remove('flashMe');
}, 1500);
})(b); // Pass `b` to the inner function.

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)

Using setInterval in JavaScript without using an inline, anonymous function

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

Categories