Applying `.css()` after a delay does not result in the styles being applied

I was experimenting with changing the background-color of a div dynamically using jQuery's css() method and it worked perfectly. However, when I attempted to add a delay to the color change, it suddenly stopped working. What could be causing this issue? Below is a simplified version of my code:

HTML:

<div id="nodelay"></div>
<div id="delay"></div>

JS:

$("#nodelay").hover(function() {
       $(this).css("background-color", 'gray');
     });

$("#delay").hover(function() {
    setTimeout(function() {
        $(this).css("background-color", 'gray');
    }, 500);
});

Link to jsFiddle Example

Answer №1

As referenced in the MDN documentation:

The issue with "this"

When code is executed by setTimeout(), it operates within a separate execution context compared to the function where setTimeout was called from. The standard rules for setting the this keyword for the called function apply, and if this hasn't been defined in the call or via bind, it defaults to the global (or window) object outside of strict mode, or becomes undefined in strict mode. It does not retain the same value as the this in the function calling setTimeout. (Emphasis added)

Due to functions passed to setTimeout being executed in a different context, the binding of this is lost. Therefore, this actually points to window (or undefined in strict mode). Essentially, it equates to performing $(window).css(...), which is unintended.

To address this, one can utilize Function.prototype.bind to bind the context of this as previously discussed. According to the documentation:

The bind() method generates a new function that, upon invocation, has its this marked to the specified value

Given that this external to the setTimeout function is the element (given that jQuery handles this through explicit this binding as seen here), utilizing $(this) will target the #delay element:

$("#nodelay").hover(function() {
  $(this).css("background-color", 'gray');
});

$("#delay").hover(function() {
  setTimeout(function() {
    $("#delay").css("background-color", 'gray');
  }.bind(this), 500);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="nodelay">Test</div>
<div id="delay">Test</div>

Alternatively, you can pre-capture this before entering the anonymous function, or explicitly name the element in the selector. If utilizing ES6, another technique involves leveraging arrow functions, which do not have their own this bound, instead directly refering to the enclosing context's.

Answer №2

Understanding the concept of this within a function can be tricky, especially after a delay. There are various approaches to resolving this issue, each with its own set of advantages. Personally, I find using the Function.prototype.bind() method to be the most effective. By using this method, you can bind the function's this reference to a specific object.

Explaining why this method works can be complex, but simply put, the this parameter passed to .bind() is the same as the this called within the .hover() function.

$("#nodelay").hover(function() {
  $(this).css("background-color", 'gray');
});

$("#delay").hover(function() {
  setTimeout(function() {
    $(this).css("background-color", 'gray');
  }.bind(this), 500);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="nodelay">t</div>
<div id="delay">t</div>

Another approach that people take is by defining a variable outside of the function where the this reference is causing issues. Due to the nature of JavaScript's scope, any functions declared after that variable declaration can access it.

$("#nodelay").hover(function() {
  $(this).css("background-color", 'gray');
});

$("#delay").hover(function() {
  var self = this;
  setTimeout(function() {
    $(self).css("background-color", 'gray');
  }, 500);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="nodelay">t</div>
<div id="delay">t</div>

Answer №5

Impressive insights shared by others. While the issue with the use of 'this' context has been pointed out by others, I won't delve further into it. Instead, allow me to introduce you to an alternative and highly beneficial jQuery $.proxy() function. This function enables you to define the context of your choice. The first argument of the proxy function is the function to be executed, followed by the desired context and any additional arguments required for the function. Give the example below a try:

$("#nodelay").hover(function() {
       $(this).css("background-color", 'gray');
     });

$("#delay").hover(function() {
    setTimeout($.proxy(function() {
        $(this).css("background-color", 'gray');
    }, this) , 500);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="nodelay">t</div>
<div id="delay">t</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

In search of a fresh and modern Facebook node template

I've been on the hunt across the internet for a quality node.js Facebook template, but all I seem to stumble upon is this https://github.com/heroku/facebook-template-nodejs. It's okay, but it's built using express 2.4.6 and node 0.6.x. I wan ...

Sending a URL via jQuery with unusual navigation

Today I was working on some code and encountered a unique URL format that has me a bit stumped. The route looks like this... /////////////////////////////////////////// // route: /member/{0}/characters /////////////////////////////////////////// public Ac ...

Using Javascript to extract data from the <pre> tag and store it into an array

Our report pages are set up to display information line by line at the bottom by appending a <pre> tag. For example: <pre> Site Report Info Any errors will appear as numbers: 938109283091238109281092 Account ID will be shown here. Acc ...

Issue with Async pipe when utilizing autocomplete functionality

HTML Code <mat-form-field> <input type="text" matInput class="formControl" [formControl]="name" [matAutocomplete]="auto" > <mat-autocomplete #auto="matAutocomplete"> <mat-option *ngFor="let option of city | async" [valu ...

Update the div using AJAX following the form submission

I'm having trouble displaying the loading image before every AJAX response when I submit the form. Currently, the image only shows on the first submission. Here's the code I'm using: $('form.ajax').on('submit', function ...

Unable to pass observable data when closing the pop-up

return{ // The following code can be found in index.js addItem: function () { alert("working"); Newram.show().then(function (response) `***// Calling show functionin Newram.js***` { var c = response; ...

Tips for reducing the size of Javascript code upon clicking a button while also implementing validations

I need help with a textEditor feature. I want users to be able to write Javascript functions, and when they click a button, the code should be validated for correct syntax and then minified. This functionality needs to be implemented using either Javascrip ...

Instructions for changing the color of the final character in a placeholder

Can you change the color of the last character in a placeholder text? I couldn't find any solutions related to this. <input type="text" class="f_name" name="fname" placeholder="First Name*"> It should look like the image below https://i.sstat ...

Automating the selection of a drop down based on a condition in Angular 2: A step-by-step guide

I'm facing an issue with a drop-down menu where no default value is selected. On my homepage, I need to automatically select an option based on query parameters. I've attempted various methods but none have been successful. Below is the code snip ...

Instead of loading JSON contents using jQuery AJAX at page load, consider loading it dynamically while typing in the search box

It's odd that there is an XHR request for search results as soon as my page loads. Even though it's hidden from the user, a substantial amount of json data is being loaded. Take a look at my code: $.ajax({ type: "POST", url: "http://localho ...

Using Node.js, you can leverage regular expressions to swap out the data within parentheses in a sub

I'm looking for a way to update the table name inside a subquery using regex in node.js. For instance, transforming the given query: SELECT col1 FROM (SELECT col1::DECIMAL(10), col2, FROM @table_name) WHERE (COND1) AND (COND2) Into: SELECT col1 FROM ...

Is there a way for me to insert a variable into the src attribute of my img tag like this: `<img alt="Avatar" src=`https://graph.facebook.com/${snAvatarSnuid}/picture`>`

I need assistance with passing a variable called snAvatarSnuid within the img src tag, specifically after facebook.com/ and before /picture as shown below: <img alt="Avatar" src=`https://graph.facebook.com/${snAvatarSnuid}/picture`> Note: 1) The ht ...

What are the advantages and disadvantages of using the picture element in web design?

What advantages and disadvantages come with using the HTML5 picture element? Specifically, does the browser download all images or only the image that matches the media query? ...

Numerous datasets of bubble charts available for use in chartjs

I have an array named main_arr that contains multiple data arrays. To visually represent these different arrays, I am utilizing a bubble chart where each one is displayed in a distinct color. var myBubbleChart = new Chart(ctx, { type : 'bubble&a ...

Enhance your Vue PWA by utilizing ServiceWorker to efficiently cache remote media assets fetched from an array of URLs

In my PWA development project, I am looking to provide users with the option to download and cache all media assets used in the application. However, the default behavior of PWAs only caches assets when they are requested during app navigation. My goal is ...

"I'm experiencing an issue in Laravel where the Ion range slider's color and dragger are

I'm currently implementing ion-rangeslider into my project. Here is the HTML code I've used: <div style="position: relative; padding: 200px;"> <div> <input type="text" id="range" value="" name= ...

How can I update a particular label with Ajax?

I have encountered an issue where I am attempting to dynamically update a label every 5 seconds using AJAX and interval in my Webforms application. However, the label only updates when I manually refresh the page. It does not change without reloading the p ...

Are you experiencing a strange problem with the CSS button when hovering, clicking, or with the border?

Check out the code for this implementation on jsfiddle: https://jsfiddle.net/xuhang1128/cmkbu07s/2/ I utilized React and React-bootstrap to create it. .design2-statusMonitor { margin-top: 20px; .list-group-item { display: inline-block; ...

Guide on leveraging event delegation to trigger a function depending on the id of the clicked element

Although I have experience with event delegation, I am currently facing a challenge in setting up a single event listener that can execute one of three functions based on the ID of the element clicked. Here is the existing code without event delegation: ...

Guide to importing JavaScript in an npm package using TypeScript and JavaScript

I recently downloaded a library that includes both Typescript and its corresponding javascript version. Despite trying to declare import Library from "@scope/library", my application is only able to access the Typescript version, even after adding the .js ...