1

1) The code seems simple but method chaining doesn't work:

$('.button').on('click', function(){
$(this).removeClass('shadow').delay(500).addClass('shadow');
 });

2) This one doesn't work either:

$('.button').on('click' ,function() {
   setTimeout(function() {
    $(this).removeClass('shadow').addClass('shadow');
  }, 500);
});

3) But this one does!

$('.button').on('click' ,function() {
   var shadow = $(this).removeClass('shadow');
   setTimeout(function() {
   shadow.addClass('shadow');
   }, 500);
   });

I'd like to ask more experienced coders: What's wrong with 1? What kind of additional action does var in 3 that is obsolete in 2? This case turns my var understanding upside down because I thought that var is only some kind of data holder.

Seemax
  • 121
  • 12
  • In the last example you copy the element into shadow. Use a var to store the element before you execute the setTimeout – mplungjan Mar 01 '16 at 08:55

2 Answers2

4
  1. Your first snippet is not working, because .delay() can be used to delay the animation queue not others, That is addClass here.

  2. The problem with second snippet is, Inside a setTimeout, the this will point to window. So technically you are removing a class from window, not from the element that you want. For overcoming this issue you can do two different things,

  3. And your third snippet is working, because accidentally you created a closure there. So even after the execution of the click event handler the variable that you are using inside of setTimeout will be preserved.

Better solution for this context would be,

Collect the this outside of setTimeout in a variable and use it inside

$('.button').on('click' ,function() {
   var $this = this.removeClass('shadow');
   setTimeout(function() {
    $this.addClass('shadow');
  }, 500);
});

Use bind to change the context inside of setTimeout,

$('.button').on('click' ,function() {
   $(this).removeClass('shadow');
   setTimeout(function() {
    $(this).addClass('shadow');
  }.bind(this), 500);
});

Or with the recent arrow function, you can do like,

$('.button').on('click' ,function() {
   $(this).removeClass('shadow');
   setTimeout(() => {
    $(this).addClass('shadow');
   }, 500);
});
Rajaprabhu Aravindasamy
  • 66,513
  • 17
  • 101
  • 130
  • Thanks for explanations and for relevant links but, sorry to say, neither .bind(this) nor arrow function works for me. Take a look, please http://codepen.io/462960/pen/avqjoe/?editors=1010 – Seemax Mar 01 '16 at 10:21
  • @ВладимирМаксименко See this demo, http://codepen.io/anon/pen/oxgEOq?editors=1010 – Rajaprabhu Aravindasamy Mar 01 '16 at 10:25
  • Thanks for updating and presenting '.bind()' and 'arrow function'. It remains to be more explored by me in depth but, at the first glance, I noticed no advantage of 'arrow function' vs regular 'setTimeout()'. Is there any? – Seemax Mar 01 '16 at 11:03
  • @ВладимирМаксименко arrow function makes code more concise. And the the scope which executes the arrow function will be served as `this` inside that function. – Rajaprabhu Aravindasamy Mar 01 '16 at 11:06
0

.delay(time) is used when you have animation in queue. But in your case you are adding/removing a property/attribute value.

So, you need to use the delay of setTimeout() like:

$('.button').on('click', function(){
   var $t = $(this);
   $t.removeClass('shadow');
   setTimeout(function(){ $t.addClass('shadow'); }, 500);
});
  1. Issue with first one is that adding/removing property/attribute value doesn't get added in queue.
  2. Issue with second one is that the anonymous function in the setTimeout has its own scope and $(this) doesn't refer to the $('.button').
  3. Issue with the third one is that you don't have a reference to the element in the shadow variable. This is most likely to work if you do var shadow = $(this); check below:

$('.button').on('click' ,function() {
   var shadow = $(this);
   shadow.removeClass('shadow');
   setTimeout(function() {
      shadow.addClass('shadow');
   }, 500);
});
Jai
  • 74,255
  • 12
  • 74
  • 103