0

when I load a image and loading fails, I try to reload after a delay using setTimeout, as below:

$('img').error(function(){
    setTimeout(function(){
        $(this).attr('src', $(this).attr('src') + '?' + Math.random());
    }, 3000);
});

But this solution doesn't reload the image as expected.

nbrooks
  • 18,126
  • 5
  • 54
  • 66
JuanPablo
  • 23,792
  • 39
  • 118
  • 164

2 Answers2

3

this is no longer referring to $("img") you need to assign a varialbe as a placeholder for this

$('img').error(function(){
    var $self = $(this);
    setTimeout(function(){
    $self.attr('src', $self.attr('src')+'?'+Math.random());
    }, 3000);
});
Howard Renollet
  • 4,609
  • 1
  • 24
  • 31
  • This always mystified me. Why is it that `$(this)` refers to the image when you do the variable assignment, but to something else when you run the `.attr()` method? – PaulProgrammer Nov 07 '14 at 21:04
  • @Paul It doesn't refer to the image in either case; `this` would be the same in both those cases, because the scope hasn't changed there. – nbrooks Nov 07 '14 at 21:06
  • querystring is wrong.... going to be ...gif?312321?234234234?234234234?234234234?23423423423?234234234?@3423234 after a few iterations. – epascarello Nov 07 '14 at 21:07
  • the value of `this` is determined by how a function is called. If the function doesn't explicitly assign the value of `this` (and you're not in strict mode), then `this` will refer to the global object. If you call a function on an object, `this` will then refer to the object that the function was called on. The value of `this` changes when we call the anonymous function inside of `setTimeout()`. – Howard Renollet Nov 07 '14 at 21:12
  • What's happening here, is we are calling a function on each `img` node via jQuery. Since a method is being called on an object, `this` refers to the object. If we call a new function, the value of `this` changes depending on how it was called. In this case, since we don't explicitly define `this`, it would be the global object. I hope that helps clarify @PaulProgrammer – Howard Renollet Nov 07 '14 at 21:16
2

The value of this changes to window in your inner function scope. Save a reference to the jQuery wrapper of your image when the outer function is triggered.

$('img').error(function() {
    var $img = $(this);
    setTimeout(function(){
        $img.attr('src', $img.attr('src') + '?' + Math.random());
    }, 3000);
});

Edit:
As @epascarello pointed out, you're assuming there aren't any existing query params already on the image when you append ?randomNum. If you know that will always be the case, that's fine, although the param really should be ?key=randomNum. If it's possible that there are existing params, you'll have to do something similar to the below. (But do you really need to append a random number to the URL?).

function updatedSrc(oldSrc) {
    var delim = (oldSrc.indexOf('?') != -1) ? '&' : '?';
    return oldSrc + delim + "rand=" + Math.random();
}

And when you update the src you would do $img.attr('src', updatedSrc($img.attr('src'))).

nbrooks
  • 18,126
  • 5
  • 54
  • 66
  • @epascarello Ah good point, I didn't catch that, that could also be an issue – nbrooks Nov 07 '14 at 21:11
  • Of course, this still isn't ideal for appending query params. You can see [this answer](http://stackoverflow.com/questions/486896/adding-a-parameter-to-the-url-with-javascript) for a more full-featured solution. This should be good enough for this scenario. – nbrooks Nov 07 '14 at 21:26