Retrieving data from a variable created by a Factory that triggers an asynchronous request

I have a scenario where one factory sends a POST request to receive key-value pairs in JSON format:

.factory('DataFetcher', ['$resource',
function($resource) {

    // Returns JSON key-value pairs, for example "{'foo', 'bar'}"
    return $resource('api/fetch-data', {}, {
        get: {
            method: 'POST'
        }
    });

}])

Another factory is designed to be used by controllers to access a specific value based on its key:

.factory('ValueAccessor', ['DataFetcher',
function(DataFetcher) {

    var data;

    DataFetcher.get(function(response) {
        data = response;
    });

    return {
        get: function(key) {
            return data[key];
        }
    };

}])

The issue arises when calling ValueAccessor.get('foo'), the data object from the ValueAccessor factory is not initialized yet (as DataFetcher.get is asynchronous), resulting in a

TypeError: Cannot read property 'foo' of undefined
:

.controller('SomeController', ['ValueAccessor',
function (ValueAccessor) {

    console.log(ValueAccessor.get('foo')); // error

}])

Any suggestions on how to resolve this situation?

Answer №1

It was mentioned in your query that Rest.get operates asynchronously, requiring your Pairs.get to also be asynchronous. Below is a possible implementation:

.factory('Pairs', ['Rest', '$q',
function(Rest, $q) {

var pairs;
var deferredList = [];

Rest.get(function(response) {
    pairs = response;
    angular.forEach(deferredList, function(o) {
        o.deferred.resolve(pairs[o.key]); // resolve saved defer object
    });
    deferredList = null; // list no longer needed
});

return {
    get: function(key) {
        if (pairs) {
            return $q.when(pairs[key]); // convert immediate value to promise
        }

        var deferred = $q.defer(); // creating a deferred object for later resolution
        deferredList.push({ // save key and deferred object for later use
            key: key,
            deferred: deferred
        });
        return deferred.promise;
    }
};

}])

To utilize this, you can follow this example:

Pairs.get('foo').then(function(value) {
    console.log(value);
});

Answer №2

When dealing with asynchronous functions, it's important to wrap them in a promise for better control. Below is an example of how I have implemented a similar solution. Please remember that safeApply triggers the $digest cycle to allow Angular to react to any data changes it is monitoring.

 var safeApply = function (scope, fn) {
                    if (scope.$$phase || scope.$root.$$phase) { 
                        fn(); 
                    } else {  
                        scope.$apply(fn); 
                    }
                };

ret.getAll = function(type) {
    var deferred = $q.defer();
    var where = "apm_type = '" + type + "'";

    query(type, where, function(err, response) {
        var objs = [];
        if (err) {
            safeApply($rootScope, function() { deferred.reject(err);});
        } else {
            safeApply($rootScope, function() { deferred.resolve(response);});
        }

    }); 
    return deferred.promise;
};  

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

What methods should I use to modify the upcoming array of objects?

I have been struggling with this exercise for about an hour now, and I can't figure it out. Can someone please help me with this? Here is the array that I retrieved from the database: View Base Array Image let data = [ { "name": "October : 2019", "u ...

Troubleshooting Vue.js data binding problems

Utilizing HTML targeting with data binding <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <div class="row" v-for="test in tests"> <div class="col-12"> <router-link tag="a" :to="{ name: ...

What steps can be taken to verify that observables from distinct components have been fully executed?

I am faced with a situation where multiple components on a page are utilizing observables to fetch API data. I have implemented a loading service that is responsible for displaying a loader from the time the first observable is initiated until the last one ...

Ways to halt the repetition of clicking the like button on my social media posts

I've been working on a new post system that allows users to like posts. Everything seems to be in order except for one issue - when iterating through the likes table from the post-like relation, the like button is being duplicated even with added cond ...

The powerful trio of Node.js, Express.js, and Socket.io synergistically

Struggling to establish a realtime connection with socket.io to monitor a redis db for new items on a list. Any suggestions? app.js /** * Module dependencies. */ var express = require('express'); var http = require('http'); var pat ...

Strategies for halting the return of a JavaScript function until all AJAX requests have been completed

function processData(data) { //perform some data processing return data; } function test() { $.ajax({ 'url': api1, 'data': { 'use': "200" }, 'dataType': ' ...

Setting a cookie in a browser using an AJAX response: A step-by-step guide

When utilizing a Javascript function with jQuery to send a POST request to a web service, the response from the web server includes a header "Set-Cookie: name=value; domain=api.mydomain.com; path=/", along with a JSON body. However, despite this expected ...

Exploring the Depths of Scope Hierarchy in AngularJS

Upon inspecting the _proto__ property of an object I created, it is evident that it has been inherited from Object. https://i.stack.imgur.com/hcEhs.png Further exploration reveals that when a new object is created and inherits the obj object, the inherit ...

Baffled by the intricacies of jQuery

As a newcomer to jQuery, I stumbled upon this code snippet and am curious about its function. It seems like it is replacing an element with the id reveal to a link with the class html5lightbox and id reveal. However, the part that puzzles me is $( '#r ...

Interact with embedded elements in JavaScript by using the onClick event

Here is a JavaScript code snippet I've been working on: <div> <tr onClick="click1()"> <td> click 1 </td> <td onClick="click2()"> click 2 < ...

Duplicate key error in Node.js/Express with req.param

Whenever my node.js/express server encounters an error due to the failure of saving an object (through a post request), I noticed that the req.param key ends up being duplicated. Take, for instance, my node.js code: User.create({ username: req.param("use ...

JavaScript-based tool for extracting content from Sketch file

My goal is to extract the contents of a .sketch file. I have a file named myfile.sketch. When I rename the file extension to myfile.zip and extract it in Finder, I can see the files inside. However, when I try the same process on the server using Node.js ...

Iterating through a jQuery function to increment value

I have encountered an issue while trying to calculate the total value from an array of form fields. The problem lies in how the final value is being calculated on Keyup; it seems that only the last inputted value is being added instead of considering all t ...

Connect to the Kendo dropdown list undefined

I am looking to automatically bind a model to a Kendo dropdown list. The model is retrieved from the server and can sometimes be undefined or a valid object. My problem arises when the value is undefined. In this case, Kendo selects the first item in the ...

The state variable is not accurately captured as it passes through various components

For the sake of readability, I have omitted certain sections of my original code. Apologies if this leads to any confusion! In App.js, there is a state variable defined as follows: const [tasks, setTasks] = useState([]) From App.js, the state varia ...

What could be causing my jQuery event handler to not work properly when connected to numerous elements?

I have implemented jquery to dynamically add multiple "addTask" form elements to a "ul" on the webpage every time a link is clicked. $('span a').click(function(e){ e.preventDefault(); $('<li>\ <ul>\ ...

Automatically navigate to a new page once form submission is successful and posts have

Within my webpage, I have an attribute called onSubmit that is responsible for handling the submit event. The functionality of the submit and the page element are outlined below. Upon submission, the first step is to initiate a post request for a ruleset, ...

React blogging site's administrative dashboard

https://i.sstatic.net/M6fUJ.png I am currently in the process of developing a blogging platform using MERN technology. Specifically, I am focused on creating a restful API with Node.js, Express, and MongoDB. The frontend, built with React, consists of thr ...

Basic AngularJS program: Displaying a issue in Gruntfile.js

$ grunt connect:development:keepalive ERROR: Running "connect:development:keepalive" (connect) task Warning: undefined is not a function Use --force to continue. Aborted due to warnings. I am currently studying AngularJS from the book Profes ...

Arrange array items according to the values of two attributes

Within my array of N objects, each object is structured with the following properties: { id: 'an id', description: 'a description', isUser: true/false } My goal is to sort this array based on two criteria: Firstly, any object w ...