Understanding the bounds of "this" within the asynchronous function of an Ionic Angular application

When trying to run a function that is not found, I discovered that saving a reference to the function in a separate variable is necessary:

   function updateCheck() {
            if (this.isNewVersionNeeded()) {
                var buildFunc = this.buildObject();
                this.updateBiography().then(function(){
                    buildFunc();
                })
            } 
        };

I realized that the buildObject function only works when saved and executed via the variable before calling this.updateBiography, which is an asynchronous function. The following code snippet does not achieve the desired outcome:

           function updateCheck() {
                if (this.isNewVersionNeeded()) {
                    this.updateBiography().then(function(){
                        this.buildObject();
                    })
                } 
            };

All functions are exposed through a service object:

 var service = {
            all: all,
            updateBiography: updateBiography,
            get: get,
            updateCheck: updateCheck,
            isNewVersionNeeded:isNewVersionNeeded,
            buildObject:buildObject
        };
        return service;

Before executing buildFunc, when logging the "this" object, it logs as window/global scope. Why does this happen and how can it be resolved? I am looking for a solution where I don't have to store all my async methods separately just to remember them. How should I address this issue?

This is the entire service script:

(function () {
    angular
        .module('biography.services', [])
        .factory('Biography', Biography);

    Biography.$inject = ['$http'];

    function Biography($http) {

        var biographyObject = { } ;

        var service = {
            all: all,
            updateBiography: updateBiography,
            get: get,
            updateCheck: updateCheck,
            isNewVersionNeeded:isNewVersionNeeded,
            buildObject:buildObject
        };
        return service;

        var self = this;
        function updateCheck() {
            if (this.isNewVersionNeeded()) {
                this.updateBiography().then(function(){
                    self.buildObject();
                })
            } 
        };

        function updateBiography() {
            return $http.get("Apicall adress")
                        .then(function (resp) {
                            window.localStorage.setItem('biography', resp.data);
                            window.localStorage.setItem('biographyTimeStamp', Date.now());
                        }, function (err) {
                            console.log('ERR', err);
                        });
        }

        function all() {       
            return biographyObject;
        }

        function get(name) {
            var biography = biographyObject;
            for (var i = 0; i < biography.length; i++) {
                if (biography[i].name === name) {
                    return biography[i];
                }
            }
            return null;
        }


        function buildObject() {
            var temp = JSON.parse(window.localStorage.getItem('biography'));
            biographyObject = temp;
        };

        function isNewVersionNeeded() {
            prevTimeStamp = window.localStorage.getItem('biographyTimeStamp');
            var timeDifference = (Date.now() - prevTimeStamp);
            timeDifference = 700000;
            if (timeDifference < 600000) {
                return false;
            }
            else {
                return true;
            }
        }
    }
})();

Answer №1

When you invoke an anonymous function, the context of its this keyword is determined at a later time, not during its creation within the function scope.

A simple rule to follow is that whatever is to the left of the dot, like in myObj.doSomething(), allows doSomething to access myObj as its this.

function updateCheck() {
    if (this.isNewVersionNeeded()) {
        this.updateBiography().then(function() {

// The object on which this anonymous function is defined/invoked will become "this"

            this.buildObject(); 
        })
    }
};

If you are just passing a reference of your function and not invoking it, you can simply use this.

function updateCheck() {
    if (this.isNewVersionNeeded()) {
        this.updateBiography().then(this.buildObject);
    }
};

If this.buildObject relies on the context internally, then you can utilize

function updateCheck() {
    if (this.isNewVersionNeeded()) {
        this.updateBiography().then(this.buildObject.bind(this));
    }
};

The value of this is determined by the context (object) on which the function is invoked. An anonymous function or a function not referenced through an object defaults to having a window context. The bind function allows for explicit binding of this to a specific object reference.


Same function invoked in different contexts (on different objects)

var obj = {
    a: function () {
        console.log(this);
    }
};
var aReference = obj.a;
aReference(); // logs window, default "this"
obj.a(); // logs obj

Answer №2

The main issue at hand is that 'this' in this context specifically refers to the callback function. It is not possible to access 'this' directly inside the callback. As a result, the solution is as follows:

function Biography($http) {
      var self = this;

       function updateCheck() {
                if (this.isNewVersionNeeded()) {
                    this.updateBiography().then(function(){
                        self.buildObject();
                    })
                } 
            };

An alternative approach using ES6 syntax would be:

 function updateCheck() {
                    if (this.isNewVersionNeeded()) {
                        this.updateBiography().then(() => {
                            this.buildObject();
                        })
                    } 
                };

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

Looking for guidance on how to initiate or halt React Native Moti animation when the state changes? I've been running into issues where my method appears to disrupt

While experimenting with the Moti animation, everything was working perfectly until I included the playbackState === State.Playing condition. Unfortunately, once I added it, the animation looped only once and then stopped repeating. I'm puzzled as to ...

Understanding the time complexity of Object.entries()

Is the complexity of Object.entries() in JavaScript known? According to information from this question, it seems like it could possibly be O(n) if implemented by collecting keys and values as arrays and then combining them together? ...

Asynchronous-Synchronous Hybrid Architecture

For the past few weeks, a particular question has been consuming my thoughts, but the rush of daily life prevented me from addressing it with the clarity it deserves. I provided a hasty solution to a concerned customer to quell both his anxieties and my ow ...

What is the best way to transfer variables defined in PHP to JavaScript?

Can the variables previously defined in JavaScript be used in the line that starts with $sql =? var southWestLat = map.getBounds().getSouthWest().lat(); var southWestLng = map.getBounds().getSouthWest().lng(); var northEastLat = map.getBounds().getNort ...

Strategies for Returning Multiple Values from a Function in JavaScript

Thanks in advance I am wondering how to extract multiple values from a code block using JavaScript. I am unsure if I need to use an array or something else as I am new to JS. Please consider the following HTML code: <div class="row"> ...

What are the solutions for resolving the error "npm run build failed to compile React JS?"

Having trouble creating an optimized production build... Compilation failed. Module not found: Error: Unable to locate './App' in '/Users/qadeer/Desktop/Khazan/guardman/src' Did you mean 'App.js'? BREAKING CHANGE: The request ...

Removing a Django object via AJAX or JavaScript with a confirmation prompt

Greetings! I am looking to implement a feature in Django where I can delete an object using AJAX or JavaScript with a confirmation message upon clicking the delete button. However, I am struggling to complete the AJAX request. Here is the code in views.py ...

Creating HTML dynamically upon page load with the use of JavaScript

I have a project where I need to create a small block of JavaScript that can be embedded in various websites' home pages. This script will automatically call a URL when visitors hit the home page, collecting specific statistics and returning a small i ...

Using ng serve to upload multipart files in Angular 2

I am currently working on the front end of a file uploading service and have encountered a strange issue. When I restart the server using ng serve, it throws an error related to generated components within the app component. The error message can be seen h ...

guide to extracting data from JSON using PHP and JavaScript

http://gdata.youtube.com/feeds/users/LadyGagaVEVO/uploads?alt=json&max-results=10&format=5 I'm interested in extracting the video thumbnail and link from the above URL using PHP and JavaScript. However, I am unsure of how to accomplish this. ...

Unable to update variable values in event listener function in $rootScope

In my controller, I am utilizing $rootScope.$on to monitor an event emitted by a module called angular-packery. The event is successfully captured and I can manipulate the 'args'. However, my goal is to store the args object in a variable declare ...

Exploring the concepts of recursion and return statements in JavaScript

Currently, I am immersing myself in the world of JavaScript by taking courses on CodeAcademy.com. However, there is one exercise question that is giving me some trouble, even though I believe I have come up with the correct answer. This particular code is ...

AngularJS Material layout containing one row divided into two columns

I'm currently trying to figure out how to achieve a layout with one row containing two columns of specific width. The issue I'm facing is that columns, as used in Material design, appear more like rows to me. |-------------80%------------------ ...

showing the angular response data in a HTML table layout within a specific div element

I'm currently using the angular-fullstack generator and I've received data in response to a GET request in the form of integer values (1, 2 5, 6 134, 245 236, 567 415, 234 and so on). I'd like to display these values in an HTML t ...

I am unable to access the environment file variable values within my Node project

I'm facing an issue with accessing 2 variables in my env file for Port and MongoDB link. Despite trying various solutions from the internet, I am unable to retrieve these values in both the listen method and database connection. Below is a snippet of ...

Remove an element from an array in every object it is found in

My MongoDB document 'Org_unit' is structured as follows: { "_id": ObjectId("0894f016e6e2e073c19e051"), "allowedusers": [ "admin", "Fred", "Bob", & ...

I am puzzled as to why my compare function is failing to properly sort my objects by location, resulting in the unchanged and unsorted object

I am currently working with JSON data and facing a sorting issue. The data structure looks like this: [ { "name" : "", "location" : "home" }, { "name" : "", "location" : "office" } ] However, I am unable to sort this data using a function ...

The consequences of jQuery Ajax Memory Leaks

After reading through several other posts on the topic, I have noticed a memory leak issue when making repeated ajax calls with jQuery (every 30 seconds in my case). Switching from using $get to $post helped reduce the size of the leak, but it still occurs ...

modify the text inside a div when a radio button is clicked

Can someone help me with updating the status div based on the radio button value selected by the user? The code below isn't functioning as expected. Any assistance is appreciated. Thank you! Here is the HTML code snippet: <form action=""> ...

What is the process Wikipedia uses to transform keywords into clickable links?

Currently, I am working on a Node.js project involving a model called "tags". I am looking for a way to automatically turn any tags mentioned in comments into links leading to the relevant tag page. For instance, if a user types out "What is a chicken?", I ...