Ensure the calling object is retained during the resolution of an Angular promise

Identifying the Issue

One issue arises when resolving promises in Javascript: the context switches to Window #. This means that referring back to the object resolving the promise becomes tricky because I can't access or modify its variables.

The common workaround is using the that = this hack, but a drawback of this approach is that if multiple objects use this hack, they end up sharing the same window.that variable and confusion ensues.

Below is a snippet of code I have put together to showcase this problem:

app.js

var app = angular.module('myApp', []);
//Represents a service making server calls
//Returns Angular promises
app.service('MyService', function($q, $timeout){

    this.evenOrOdd = function(i){

        console.log("even or odd for: " + i);
        var deffered = $q.defer();

        $timeout(function(){    
                console.log("starting time out");
                if (parseInt(i)) {

                    if (i%2 === 1) deffered.resolve("Odd:" + i);
                    else deffered.resolve("Even" + i);                  
                }
                else deffered.reject("That's not an int!");
            }, 3000);

        return deffered.promise;

    };


});


//Represents some business object 
//Multiple instances may be needed
app.factory('MyFactory', function(MyService){

    return function() {

            //Object specific variable
            this.rand = Math.random();

            console.log("creating new factory object with rand = " + this.rand);

            this.oddCheck = function(i){            
                var promise = MyService.evenOrOdd(i);

                that = this;        //issue here

                promise.then(function(value){               
                    console.log(that.rand + "|" + value);

                    }
                );  

                promise.catch(function(value){
                    console.log(that.rand + "|" + value);
                });

            };


    };

});


//Controller handling updates on multiple objects simultaneously
app.controller('MyController', function($scope, MyFactory) {

    $scope.factoryObject = new MyFactory();
    $scope.factoryObject2 = new MyFactory();

    $scope.myClick = function(){    

        $scope.factoryObject.oddCheck(10);
        $scope.factoryObject2.oddCheck(11);

    };


    }
);

index.html

<!DOCTYPE html>
<html>
<head>

<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js" type ="text/javascript"></script>
<script src = "app.js" type ="text/javascript"></script>

</head>
<body  ng-app="myApp" >

    <div ng-controller = "MyController">

        <button ng-click = "myClick()">Click me</button>

    </div>

</body>
</html>

Running the code produces the following output:

creating new factory object with rand = 0.10776704256566871
app.js (line 38)
creating new factory object with rand = 0.5952598424233105
app.js (line 38)
even or odd for: 10
app.js (line 8)
even or odd for: 11
app.js (line 8)
starting time out
app.js (line 12)
0.5952598424233105|Even10   //Incorrect Rand
app.js (line 46)
starting time out
app.js (line 12)
0.5952598424233105|Odd:11
app.js (line 46)

Are there alternative methods to keep track of the object's location when promises are resolved?

Answer №1

Ensure to use var that = this; to avoid global variable conflicts - alternatively, explore the bind method as shown below:

this.oddCheck = function(i){            
    var promise = MyService.evenOrOdd(i);
    promise.then(function(value){               
        console.log(this.rand + "|" + value);
    }.bind(this));  

    promise.catch(function(value){
        console.log(this.rand + "|" + value);
    }.bind(this));

};

Additionally, the above code snippet can be simplified as follows:

this.oddCheck = function(i){            
    MyService.evenOrOdd(i)
    .then(function(value){               
        console.log(this.rand + "|" + value);
    }.bind(this))
    .catch(function(value){
        console.log(this.rand + "|" + value);
    }.bind(this));
};

Answer №2

I like to approach it this way: instead of returning a value directly, you can return an object and refer back to itself inside that object. Here's an example to illustrate this concept: http://jsbin.com/memaha/12/edit?js,console

Another option is to use Ecmascript 6 arrow functions, which provide access to the parent context. For instance:

.then(res => console.log(this.rand)//this will be outter function)

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

Changing the color of placeholder text in MUI 5 TextField

Looking to customize the text color and placeholder text color in my MUI TextField component to be green https://i.sstatic.net/NZmsi.png The documentation doesn't provide clear instructions, so I attempted a solution that didn't work: <TextF ...

Dependencies in Angular

After diving into Angular recently, I've been grasping the concepts well. However, one thing that still puzzles me is dependency injection. I'm unsure whether it's necessary to declare all components of my application (services, controllers ...

What could be causing Next.js to throw an error upon completion of the MSAL OAuth process?

I encountered an error while building a website using next.js. The site is set up for production, and after the authentication process with MSAL for Azure AD integration, I am facing the below error during the OAuth loop. As a beginner in next.js coming fr ...

The behavior of the select menu is erratic when interacting with AJAX

My dropdown menu is populated dynamically based on AJAX response: function populateDropdown(dropdownNum) { // invokeWebService using $.ajax json = invokeWebService("GET", "/webservice/dropwdownOptions"); optionsHtml = ""; $.each(json, function(count, jsO ...

Obtain information about a div element while scrolling

Looking to enhance my social feed page by adding a view count feature for each post. The challenge is figuring out how to keep track of views as the user scrolls down the page. Any suggestions? ...

Retrieving information using getStaticProps

I'm currently working on a new function that pulls data from The Guardian API, but I've hit a roadblock with an error message. Below is the response that's being returned: Furthermore, presented here is the code snippet for the asynchronous ...

Utilize the map function to extract retrieved information

I am currently working on fetching data from the newsapi website. The data is returned in an array-like object format. https://i.sstatic.net/k9YiC.png My main objective now is to iterate through this data and display it using my NewsItem component. Below ...

What could be causing the remaining part of the template to not render when using an Angular directive?

After adding my custom directive to a template on an existing page, I noticed that only the directive was rendering and the rest of the template was not showing up as expected. Even though the controller seemed to have executed based on console logs and B ...

Issue with fullcalendar: difficulty displaying events using ajax after clicking 'previous' or 'next' button

I am currently working on creating a calendar using fullcalendar. To retrieve data for the month, I make an external ajax request. Here are the key variables I utilize to render the fullcalendar: eventsJsonArray - used to load all events for the month ...

Hide the Select Column from the material-react-table

Can someone help me with hiding specific columns in the material-react-table component? I've searched the documentation but couldn't find any relevant information. import { useMemo, useState } from "react"; import { MaterialReactTable } ...

How to display and retrieve data from a JSON object using JavaScript

Having trouble retrieving input values from a JSON object and getting 'undefined' when running the code. Any suggestions or ideas would be greatly appreciated as I have tried various approaches. Additionally, I need to utilize JSON for my school ...

Exploring the implementation of the meta robots tag within Joomla 2.5's global settings

Encountering a peculiar issue with Joomla 2.5 and the Meta robots tag. Joomla seems to have a flaw where regardless of the URL, as long as there is a valid article id, it will generate a page. For instance: The id '61' is valid but leads to a ...

Invoke PHP by clicking on a button

I am facing an issue with a button I have created. Here is the code for it: <input type="submit" name="kudos_button" value="★ Give kudos"/>' To test it, I wrote a PHP script like this below the </html> tag: ...

In JavaScript, I would like to be able to input an end date and have the program calculate and display the number of days remaining until the deadline

I'm working on a school project that involves JavaScript code. I'm struggling with converting a date prompt from string to number format. As a beginner in JavaScript, I could really use some guidance. <script> enddate = prompt('Wh ...

Is the integer value included in the linear progression?

I have a unique setup where each time the user clicks a 'Done' button, 20 is added to a base number, x (..-40,-20,0,20,40,60..). This updated value of x is then saved in a database and displayed in real-time using Ajax. However, I am facing a ch ...

What are the steps to effectively utilize an interface within a TypeScript file that contains its own internal import?

Currently, I am in the process of developing a React JavaScript project using WebStorm and attempting to enable type hinting for our IDEs (including VS Code) by utilizing TypeScript interfaces and JSDoc annotations. Our goal is to potentially transition to ...

What could be causing the server to not successfully receive the ajax request?

I need to conduct integration tests on a website that routes all requests through a proxy: var express = require("express"), http = require("http"), port = (process.env.PORT || 8001), server = module.exports = express(), httpProxy = requir ...

In what rare scenarios does JS in string concatenation within insertAdjacentHTML fail to evaluate?

On a public website that I do not own, there is a piece of JavaScript code that writes a magic pixel image to the page to call an API I provided. Here's the snippet of code: n.insertAdjacentHTML('beforebegin', '<img src=& ...

The scrollbar on the side of my page seems to be malfunctioning

I'm having an issue with the collapsible sidebar and tabs on my angularjs page. The scroll bar is not appearing when there is overflow in the sidebar. I've tried setting the scrollbar height to auto and overflow-y to scroll, but it's not wor ...

Using the application router in Next.js to implement getServerSideProps()

I recently delved into utilizing Next.js 13 with the App Router, but encountered some challenges. The structure of my test application is as follows: ---/school ------/app ------/layout.tsx ------/page.tsx ---/src The ./app/page.tsx code snippet is ...