Search code examples
angularjspromiseangularjs-scopeangular-promise

How Do I Update The DOM in AngularJS (1.7.x) in Promise.all() Without $scope?


We've been trying to prepare an app at work as much as possible for a future migration from AngularJS to Angular. My understanding is that we are to avoid using $scope as much as possible. However, I'm finding a situation where I'm performing a Promise.all() and I can't figure out how to update the DOM without $scope.$apply(). Here's some pseudo code as an example.

Angular 1.7.x question: How do I get the DOM to render new values when a Promise.all() resolves? Word on the street is we're not supposed to use $scope.$apply(), but that's all I can figure out...

export class FooController {

    constructor(FooService, $scope) {
        this.fooService = FooService;
        this.$scope = $scope;
    }

    $onInit() {
        this.data = [];
        this.requests[...]; // holding some requests
        this.updateData();
    }

    updateData() {
        let promises = [];
        this.requests.forEach(i => promises.push(this.fooService.get(i)));

        Promise.all(promises)
            .then(res => {
                this.data = res;
                this.$scope.$apply();
            })
    }
}

FooController.$inject = ['FooService', '$scope'];

export const fooComponent = {
    templateUrl: templateUrl,
    controller: FooController
}

Solution

  • Use the $q service:

    export class FooController {
    
        constructor(FooService, $q) {
            this.fooService = FooService;
            this.$q = $q;
        }
    
        $onInit() {
            this.data = [...];
    
            this.updateData();
        }
    
        updateData() {
            let promises = [];
            this.data.forEach(i => promises.push(this.fooService.get(i)));
    
            ̶P̶r̶o̶m̶i̶s̶e̶.̶a̶l̶l̶(̶p̶r̶o̶m̶i̶s̶e̶s̶)̶
            this.$q.all(promises)
                .then(res => {
                    this.something = res;
                    ̶t̶h̶i̶s̶.̶$̶s̶c̶o̶p̶e̶.̶$̶a̶p̶p̶l̶y̶(̶)̶;̶
                })
        }
    }
    
    FooController.$inject = ['FooService', '$q'];
    
    export const fooComponent = {
        templateUrl: templateUrl,
        controller: FooController
    }
    

    AngularJS modifies the normal JavaScript flow by providing its own event processing loop. This splits the JavaScript into classical and AngularJS execution context. Only operations which are applied in the AngularJS execution context will benefit from AngularJS data-binding, exception handling, property watching, etc.

    ES6 promises are not integrated with the AngularJS execution context. Instead use promises created by the $q Service.