The results returned by AngularJS $q.all() come back as empty

Currently, I am working on implementing a $q.all function to execute multiple functions and then collect all the outputs in a function connected to the .then method at the end.

Even though it seems like the promises are being called in the correct sequence and the $all .then method is being executed at the end, the results variable is returning an array of null values (one for each promise in the $q.all).

You can find the JS Fiddle example at http://jsfiddle.net/QqKuk/120/, and I am using angular 1.0.1.

Below is a simplified version of the code I have:

This is my basic HTML structure, displaying some debug text and output:

<div ng-controller="MyCtrl">
    <p>{{fromThen}}</p>
    <p>{{fromThen2}}</p>
    <p>{{runOrder}}</p>
</div>

And here is my controller, where logOne, logTwo, and logThree are not identical functions:

var myApp = angular.module('myApp', []);

function MyCtrl($scope, $q, $timeout) {

var logOne = function(value) {
    $scope.fromThen = $scope.fromThen + value;
    var deffered = $q.defer();
    deffered.promise.then(function() {
            $scope.runOrder = $scope.runOrder + '.logOne()';
            $scope.fromThen = $scope.fromThen + value.toUpperCase();
            deffered.resolve(value);
            return deffered.promise;
    });

    deffered.resolve();
};

var logTwo = function(value) {
    $scope.fromThen = $scope.fromThen + value;
    var deffered = $q.defer();
    deffered.promise.then(function() {
            $scope.runOrder = $scope.runOrder + '.logTwo()';
            $scope.fromThen = $scope.fromThen + value.toUpperCase();
            deffered.resolve(value);
            return deffered.promise;
    });

    deffered.resolve();
};

var logThree = function(value) {
    $scope.fromThen = $scope.fromThen + value;
    var deffered = $q.defer();
    deffered.promise.then(function() {
            $scope.runOrder = $scope.runOrder + '.logThree()';
            $scope.fromThen = $scope.fromThen + value.toUpperCase();
            deffered.resolve(value);
            return deffered.promise;
    });

    deffered.resolve();
};


$scope.fromThen = '';
$scope.fromThen2 = 'No Value';
$scope.runOrder = '';


$q.all([logOne('One'), logTwo('Two'), logThree('Three')])
                    .then(function(results) {
                        $scope.runOrder = $scope.runOrder + '.then';
                        $scope.fromThen2 = results;
                    });

}

The current output displays:

OneTwoThreeONETWOTHREE [null,null,null] .logOne().logTwo().logThree().then

It appears that the order of execution is correct, so I am puzzled as to why I am receiving null values in the result. Could it be that I am incorrectly using defer.resolve(value)?

I have reviewed other examples but have not been able to identify the issue causing the lack of a result.

Any assistance you can provide would be greatly appreciated. As this is my first post, any suggestions on additional information to include (or exclude) would also be helpful.

Thank you. Neil

Answer №1

It seems like the issue lies in not returning promises from the log functions themselves for $q.all to properly execute. While you are resolving the promises and returning them, they are not being listened to anywhere. The functions within the .then calls are initiated by $q, and the return values should be sent to the resolution callbacks of the promises that the .then itself returns. Your promising functions need to have this structure:

var function = doSomthingDeferred(data) {
  var deferred = $q.defer();
  doSomethingDeferredWith(data).then(function(deferredResult) {
    var processedResult = processDeferredResult(deferredResult);
    deferred.resolve(processedResult);
  });
  return deferred.promise;
}

Alternatively

var function = doSomthingDeferred(data) {
  return doSomethingDeferredWith(data).then(function(deferredResult) {
    var processedResult = processDeferredResult(deferredResult);
    return processedResult;
  });
}

In your current scenario, when you doSomethingDeferredWith(data), the function is as follows:

function doSomethingDeferredWith(data) {
  var deferredMore = $q.defer();
  $scope.fromThen += data;
  deferredMore.resolve($scope.fromThen);

This action doesn't necessarily need to be deferred, as it completes immediately. However, if you were querying an $http-based service, then the deferredMore promise would be returned like so:

return deferredMore.promise;
}

After completing the above, you will receive some result as a parameter in a function referenced within the .then call on a promise, similar to the one returned from doSomethingDeferredWith:

doSomethingDeferredWith(data).then(function(deferredResult) {

Due to how $q operates, the call to doSomethingDeferredWith(data) returns a promise, and the function within .then is queued up but not executed until the current script loop ends. This means that all callbacks for resolved promises are run only after the call stack clears.

Your code currently does not return a promise in doSomethingDeferred or the log*** functions - instead, they return undefined. To resolve this, change your deffered.resolve(); calls to return deffered.promise; at the end of each log file. This way, the return values won't be undefined, but actual promises that $q can follow and execute the callback once all three promises have been resolved simultaneously. This will set your $scope.runFrom2 value to an array containing ['One','Two','Three'] as each individual promise resolves with its respective value.

tl;dr Version

Change the deffered.resolve(); calls at the end of each log file to return deffered.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

Tips for labeling subplots in PLOTLY JS

Looking for some guidance on adding titles to plots in Plotly JS. I've checked out the documentation but couldn't find anything helpful. Any tips or suggestions would be greatly appreciated! ...

Ensure that dynamic functions are accurately typed within a proxy utilizing TypeScript

I am currently working on a unique function that utilizes a Proxy with a get trap to extract functions from multiple objects. The challenge I am facing is getting TypeScript to recognize these functions at compile time so that I can add them to my interfac ...

Submitting a form using Ajax that was generated with the help of jQuery

Using a table with various rows, each row has an edit button. Upon clicking the edit button, a form is generated using ajax/json to populate the form data based on the selected row. An issue arises when setting up the ajax for this form. Although the met ...

Dynamically transform array values into an object

I'm interested in developing an algorithm that can replicate values for a specific object schema, as shown in the sample data below: let layer1 = {name: 'x', values: [{_color: '#996666', time: 0, tween: 'quadEaseIn& ...

Creating an Angular table row that can expand and collapse using ng-bootstrap components is a convenient and

I need assistance with an application I am developing, where I want to expand a table row to display details when it is clicked. The issue I am facing is that currently, all rows expand and show the data of the clicked row as seen in the image result below ...

Incorporating YouTube links into calendar events for each specific date

Our team is currently developing an online class website where our client wants to incorporate recorded classes. These recorded classes will be uploaded to YouTube in unlisted format and then linked to specific calendar dates. I will share the code for the ...

Semantic UI dropdown field not displaying selected option text

I've encountered an issue while working with React Semantic UI. I'm trying to render a dropdown and have configured it so that the selected option's text should display in the field. However, when I choose an option from the dropdown, instea ...

Escape from an iframe with the help of a buster

My website is being targeted by a code that prevents it from breaking out of an iframe. Despite trying different frame breaker scripts, I have not been successful in resolving this issue. Any assistance would be greatly appreciated. Thanks! Buster: func ...

Creating watercolor effects using JavaScript

Coffee has been the only thing on my mind lately. I've been contemplating how to replicate the essence of coffee in JavaScript. Imagine being able to fill a shape on the screen as if it were infused with the rich aroma of coffee. Is there a JavaScript ...

Sorting by number or date in indexedDB may lead to unexpected results due to the

I have set up an index in my database called time on the created_at field: var os = thisDB.createObjectStore(name, { keyPath : "id" }); os.createIndex("time", "created_at", {unique: false }); Instead of storing the time as a standard date format, I conv ...

Obtaining parameter in angular 2

I am on a mission to extract the username from a URL Within app.routing, I have set up the following route: export const routes: Routes = [ { path: 'dashboard/:username', component: App } ]; In my app component, I am attempting to retriev ...

Expanding cards with Material-UI and React seems to be a challenge when using an expander

I've recently integrated a Card component into my project, sourced from material-ui's official website. However, I'm encountering an issue where the CardHeader does not expand upon clicking. This is the structure of my Component : import ...

Struggling to right align Nav Items in Bootstrap React?

How do I adjust the alignment of my NavItem to the right? Currently, it is displaying aligned to the left. Are there any syntax errors present? <Navbar style={{backgroundColor:'#071425'}} collapseOnSelect expand="lg" variant=" ...

Iterate through the xml.documentElement in a loop

I want to show 8 men and 2 women in SVG format. However, my current function only displays one man and woman. How can I add a loop to make this work for all individuals? for (i = 0; i < Serie[n].Number; i++) { return xml.documentElement } The data arr ...

Modifying CSS content attribute in real-time

A colleague of mine has rented a webshop from a company. They have the option to select different templates and are also able to customize the CSS and add Javascript snippets. They reached out to me for help with making some modifications, but there's ...

What is the best way to adjust an image's dimensions to fit a specific screen size without distorting it on a webpage?

Currently working on a website, and the top section has a small column on the right with an image taking up the majority of the space to the left. The problem arises when the image spills over the screen size, messing up the overall layout of the page. I d ...

What are alternative ways to add an HTML snippet to an existing file without relying on jQuery?

Is it possible to inject the entire content of an HTML file, including all tags, into a specific div using only JavaScript? Alternatively, would it be necessary to append each element individually and create a function for this purpose? ...

Managing and updating arrays in VueJS2: Conditionally push new items and update only if their properties have changed

I am currently facing an issue with my form where each time a user updates a value in an input field, a new array element is created and added to the form results. I'm looking for a way to update the properties of the existing array element without cr ...

Testing a custom Angular directive that encapsulates the functionality of SlickGrid

Currently, I am working on testing an angular directive that acts as a wrapper for slickgrid. 'use strict'; describe('Unit: Grid Directive', function() { var $scope; var element; beforeEach(module('grid')); beforeEac ...

Retrieving and Showcasing information from a multidimensional array in a loop using React

Extracting data from a PostgresSQL server and organizing it into an array can be achieved using the following code snippet: var that = this; var temp = []; await fetch(req) .then(function(res) { res.json().then(function(data) { for (var i in d ...