17

Can somebody please tell me why the setTimeout used in the code below isn't working? It just runs the function straightaway.

function change_txt_font(elem, id, text_fnt){
    current_width = parseInt($('#span_text'+id).css('width')); 
    current_height = parseInt($('#span_text'+id).css('height')); 
    current_font_size = parseInt($("#span_text"+id).css("font-size"));

    parent.document.getElementById(elem+'_f').value=text_fnt;

    $('#span_text'+id).css('font-family',text_fnt);
    $('#'+elem).css('font-family',text_fnt); 
    setTimeout(adjust_for_font(id),2000);
    }

function adjust_for_font(id){
        alert("function")
        alert("id = "+id)
    new_height = parseInt($('#span_text'+id).css('height'));
    new_width = parseInt($('#span_text'+id).css('width'));
    width_ratio = parseFloat(current_width/new_width)
    height_ratio = parseFloat(current_height/new_height)
    new_font_size = current_font_size * Math.min(width_ratio,height_ratio)
    $("#text"+id).css("font-size", (parseFloat(new_font_size) - 1) + "px");
    $("#span_text"+id).css("font-size", (parseFloat(new_font_size) - 1) + "px");
    document.getElementById("form_front_text"+id).submit();
}document.getElementById("form_front_text"+id).submit();
}

Any help appreciated.

Mark_54
  • 1,273
  • 4
  • 15
  • 21

7 Answers7

46

The problem is this line

setTimeout(adjust_for_font(id),2000);

This doesn't schedule the invoking of adjust_for_font(id) but instead invokes the function directly and schedules the return value. To schedule the invocation of the function wrap the call in a lambda

setTimeout(function() { adjust_for_font(id); },2000);
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • For future readers, with ES6 you can also do `setTimeout( () => {adjust_for_font(id);}, 2000);` which can avoid issues referencing `this`. Additional info available [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#no_separate_this). – Jwok Aug 05 '21 at 19:44
6

By not putting quotes around your function, the function will process immediately, setTimeout will run (but won't process a function) and you're left wondering what on earth happened.

setTimeout is designed to run like this:

setTimeout('adjust_for_font',2000);

Or a using an anonymous function in the callback is another option:

setTimeout(function(){adjust_for_font(id);}, 2000);
Francis Lewis
  • 8,872
  • 9
  • 55
  • 65
  • '...left wondering what on earth happened' - yep that about sums up my javascript programming at the moment!! – Mark_54 Feb 08 '12 at 17:35
4

Change

setTimeout(adjust_for_font(id),2000);

to

setTimeout("adjust_for_font(id)",2000);
Michael Robinson
  • 1,985
  • 2
  • 21
  • 31
  • 1
    Not a bad suggestion but still wont work on certain versions of safari. You're best off just setting it into the function as: `setTimeout(function(){ adjust_for_font(id); }, 2000);` – SpYk3HH Feb 07 '12 at 22:44
4

This should do the trick:

setTimeout(adjust_for_font, 2000, id);

I am passing the function name, to be executed when 2000 milliseconds have passed. In your code, you are passing the result of adjust_for_font. The brackets after the function name cause it to be executed as soon as it is parsed (immediately).

osahyoun
  • 5,173
  • 2
  • 17
  • 15
  • Not all browsers support the syntax of `setTimeout()` with an argument for the function specified after the delay. Using an anonymous function as in the other answers should work in all browsers. – nnnnnn Feb 07 '12 at 23:25
3

The way you have it written, it's as if the output of adjust_for_font(id) is the input to the first parameter of setTimeout. The first parameter should be the function, not the result of the function. Try this instead...

setTimeout(function() {
    adjust_for_font(id);
},2000);
T. Stone
  • 19,209
  • 15
  • 69
  • 97
2

The SetTimeout syntax is setTimeout(function,milliseconds,param1,param2,...)

Here "function" means not the calling of the function. It should be the real function.

So you have to change your code to

setTimeout(adjust_for_font,2000,id); (note: The parameter id should pass after the milliseconds parameter)

or alternatively you can set the first parameter as bellow

setTimeout(function() { adjust_for_font(id); },2000);

Hiran
  • 698
  • 1
  • 10
  • 29
1

This is from my experiences. Just specifying setTimeout() will cause it to execute upon page load itself, even if it's parent function is not called. making it into a variable like this works..

before

function xyz(){
  //do something if needed
  setTimeout(function abc, duration);
  //setTimeout will be executed even before xyz() call
}

after

function xyz(){
  //do something if needed
  var t=setTimeout(function abc, duration);
  //this time, setTimeout will be executed upon xyz() call and not upon pageload
}
  • JS is idiotic, but this beats almost everything i've seen! Although...this was the fix in my case, so you have my thanks! – Cowwando May 19 '20 at 17:54