Getting the true reference of "this" in Typescript

I'm currently working through the tutorial on learn.knockoutjs.com and I've reached step 4 of the custom bindings tutorial. In the provided JavaScript code snippet, we have:

update: function(element, valueAccessor) {
    // Give the first x stars the "chosen" class, where x <= rating
    var observable = valueAccessor();
    $("span", element).each(function(index) {
        $(this).toggleClass("chosen", index < observable());
    });
}

I've converted this to TypeScript as follows:

update: (element, valueAccessor) => {
    var observable = valueAccessor();
    $("span", element).each(index => {
        $(this).toggleClass('chosen', index < observable())
    });
}

This results in creating a _this variable to maintain the scope of the "update" function instead of the inner "span" function.

update: function (element, valueAccessor) {
    var _this = this;
    var observable = valueAccessor();
    $("span", element).each(function (index) {
        $(_this).toggleClass('chosen', index < observable());
    });
}

The issue arises with $(_this). How can I ensure TypeScript provides me with the correct $(this)?

Answer №1

Many find that using TypeScript's `(_this)` is more intuitive, as code like the following often leads to multiple duplicates on Stack Overflow:

  update: function() {
     $(elem).click(function(){
          this.save();
     });
  }

The `this` in JavaScript does not behave the same way it does in other languages - it has a separate binding for every function call.

TypeScript can help make the above code work as expected for many newcomers to JavaScript:

  update: function() {
     //this refers to the object with update and save methods
     $(elem).click( () => {
          this.save();  //this still refers to the object with update and save methods
     });
  }

There are ways to refer to what you want even when using fat arrows:

update: function() {
    $(elem).click( (event) => {
        $(event.currentTarget).hide() //equivalent to $(this).hide() with a normal function
        this.save(); //Remains intuitive for non-JavaScript developers
    });
}

Or with another example:

update: function() {
    $("span", element).each( (index, elem) => {
        $(elem).toggleClass('chosen', index < observable())
        this.save(); //still intuitve for non-JavaScript developers
    });
}

Of course, for experienced JavaScript developers accustomed to the behavior of `this`, it may not be as intuitive.

By the way, I am not entirely sure about the TypeScript syntax...

Answer №2

The solution is straightforward. Avoid utilizing a lambda function in this case.

update: (element, valueAccessor) => {
    var observable = valueAccessor();
    $("span", element).each(function (index) {
        $(this).toggleClass('chosen', index < observable())
    });
}

It's worth noting that instead of using a lambda function, this code opts for

... element).each(function (index)...
.

I am unsure about the reason behind this decision, so it would be helpful if someone could provide an explanation.

Answer №3

Esailija's approach is the way to go: avoid using $(this) within the callback function. It will result in cleaner code if you use a named parameter instead.

Here's an example to illustrate how this can improve readability, using a simple jQuery plugin:

// Apply a random opacity to each element in a jQuery selection
jQuery.fn.randomOpacity = function() {
    return this.each( function() {
        $(this).css({ opacity: Math.random() });
    });
};

The code above can be quite confusing with this being used on consecutive lines and carrying different meanings.

To enhance clarity, opt for the named parameter:

// Apply a random opacity to each element in a jQuery selection
jQuery.fn.randomOpacity = function() {
    return this.each( function( i, element ) {
        $(element).css({ opacity: Math.random() });
    });
};

By incorporating the named parameter, the code becomes much more understandable.

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

Guide to using Javascript to dynamically insert items into the shopping cart menu list

Greetings! I am diving into the world of JavaScript and currently facing a challenge while working on my eCommerce website project to enhance my web development skills. My query pertains to creating a dynamic system where, upon a user adding items to their ...

The initial request does not include the cookie

My server.js file in the express application has the following code: var express = require('express'); var fallback = require('express-history-api-fallback'); var compress = require('compression'); var favicon = require(&apos ...

When extracting information from a table within a Vue.js and Vuetify.js function

When trying to display a table, only one row is being printed. How can I resolve this issue? I have attempted various solutions (Vanilla JS worked). This project is for educational purposes and I am relatively new to JS and Vue.js. <template> < ...

Utilize the gsap ScrollTrigger in conjunction with React's useRef() and Typescript, encountering issues with type mism

Recently, I've been trying to add some animation to a simple React Component using the GreenSock ScrollTrigger plugin. However, I ran into an issue due to types mismatch in my Typescript project. Here's a snippet of the code: import React, {useRe ...

Unexpected Error in Applying Color to Rows in EXTJS Grid

Currently, I am utilizing extjs 3.2 and recently experimented with a sample for coloring grid rows by referring to . I added a grid view configuration in the gridExample.js file which holds a static grid. viewConfig: { stripeRows: false, get ...

Guide on preventing radiobutton postback in ASP.NET based on specific conditions on the client side

I have a radio button list set up in my form. Upon selecting an option, a postback occurs followed by the execution of some business logic. However, I am facing an issue where I need to prompt the user for confirmation when they select a radio button optio ...

A guide on incorporating AJAX with jQuery to fetch a JSON file

I am struggling to incorporate a json file into my code using ajax. Despite my efforts, I can't seem to get it to work as I'm not well-versed in ajax and JQuery. The json file contains an array that I need to utilize in various sections of the j ...

What is the reason that .every() is not recognized as a function?

I have gathered a collection of required form elements and have added a 'blur' listener to them. var formInputs = $(':input').filter('[required]'); formInputs.each(function(i) { $(this).on('blur', function ...

Discord.js experiences limitations with storing multiple data in conjunction with TypeScript when using MySQL

Question Currently, I am developing a Discord bot to track messages using typescript and discord.js. I have included my code below. The issue I am facing is that the data is not being saved correctly. Each time a user sends messages, their message count i ...

Tips for sending a file via Ajax using the POST method?

While there is no shortage of information on this topic, I am interested in discussing the process of uploading a file to a server using Ajax or a similar method. # HTML <form method="post" id="Form" enctype="multipart/form-data"> {% csrf_token %} ...

Is there a way to remove the messages I've selected using checkboxes in jQuery?

I'm currently developing a messaging system that heavily utilizes AJAX. One of the features I'm working on is implementing bulk actions with checkboxes. The checkboxes have been added successfully, but I'm facing an issue in figuring out how ...

The function mustAsync onSuccess is not present in this type (typescript)

I currently have 2 mutations that are functioning well. However, I encountered an issue when attempting to implement onSuccess and invalidateQueries. The error message displayed is as follows: Property 'mutateAsync' does not exist on type '{ ...

Issue: The error message "undefined variable 'angular'" appears when attempting to access offline files stored on a network drive

I have successfully developed offline forms using angular js v1.6.4, angular-ui-bootstrap, and angular-ui-router without the need for server hosting. When the package is saved on local storage, it functions perfectly on both IE and Chrome browsers. Howeve ...

Validating Cognito credentials on the server-side using Node.js

I am currently developing server-side login code for AWS Cognito. My main goal is to verify the existence of a user logging into the identity pool and retrieve the attributes associated with them. With email login, everything is running smoothly using the ...

What is the best way to continuously call a URL using jQuery until the desired result is obtained?

I have a jQuery script that interacts with a Jenkins web server to initiate a build process. The duration of this build process is unknown, and one way to determine if the build is completed is by checking the JSON API for the status key "building." If thi ...

Change the class of the div when the first div is selected

My goal is to switch the class of the #klapp element (from .klapp to .klappe) whenever a click event happens inside the #label-it container, including when the #klapp element itself is clicked. The challenge is that I am not able to use unique IDs for each ...

Modify the placeholder color for a disabled Input element to match the overall Mui theme design

I am struggling to change the color of the placeholder text in a disabled input field within my app's theme. Despite attempting to target the MuiFormControl, MuiInputBase, and MuiInput components in my theme.tsx file on CodeSandbox, I have not been su ...

Configure the right-to-left directionality for a particular widget only

Is it possible to align the label inside a TextField component to the right, similar to "labelPlacement" on FormControlLabel? I am aware of using the RTL library with mui-theme, but that applies to the entire application. Is there a way to apply it to jus ...

The GET Request made for an Image in an Angular Component results in a 404 error message indicating

I have been working on uploading and fetching images from my mongodb database. Utilizing multer for the image uploads, along with express and mongoose for handling GET/POST requests has been successful so far. The process involves uploading the image to th ...

Retrieve the content from paragraph elements excluding any text enclosed within span tags using the Document.querySelector method

Exploring the following element structure: <p> <span class="ts-aria-only"> Departure </span> RUH <span class="ts-aria-only">&nbsp;Riyadh</span> </p> In an attempt to extract the text RUH, it has been disc ...