Search code examples
angularjsangular-promise

component not picking up new state of a variable changed inside a resolved ES6 promise call


This is my first angularjs application that I am updating but not working well. Basically i have a spinner that I need to show when calculating then turn it off. My promises are resolving well but the component does not pick up the new value. If I click a button that actually changes the loading variable, it does work in that the component picks up the false value.

But I want it to be turned off once the promise is complete. It does resolve and I do reach the vm.loading = false value well but the component don't get that new value.

(function () {

    var app = angular.module('APP').controller('APPController',
    ['$q', '$scope', '$http', '$timeout', '$location', '$filter', 'dataservice', '$routeParams', controller]);

    function controller($q, $scope, $http, $timeout, $location, $filter, dataservice, $routeParams) {

        // The controller's API to which the view binds
        var vm = this;
        vm.loading = false;
        vm.data = null; // GET THIS FROM API
        getSettings();

        function getSettings() {

            vm.loading = true;

            var pArray = []; // promises Array
            var p1 = vm.ds.fetchExstingSettings(10);
            pArray.push(p1);

            $q.all(pArray)
                .then(function (data) {
                    // get api data now    
                    fetchData().then(done => {
                        vm.loading = false; // reaching here well
                    })    
                })
                .catch(
                function (err) {
                    alert(err);
                    return null;
                })
                .finally(function () {    
                    $timeout(function () {
                        vm.searchLoading = 0;
                        $scope.$apply();
                    });
                });
        }


      async function fetchData() {    
          var result = await $http.get('http://localhost:4228/Api/data');
          vm.data = result;             
      }    
      function saveChanges() {
          vm.loading = false; // this works     
      }    
    }
})();// JavaScript source code

html:

<div class="text-center" ng-if="vm.loading == true">
    <i class="fa fa-spin fa-spinner fa-5x"></i>
</div>

Solution

  • The ES6 promises used by async / await are not integrated with the AngularJS framework and its execution context. Only operations which are applied in the AngularJS execution context will benefit from AngularJS data-binding, exception handling, property watching, etc.

    One approach is to wrap the ES6 promise in $q.when:

      $q.all(pArray)
        .then(function (data) {
            // get api data now    
            $q.when(fetchData()).then(done => {
                vm.loading = false; // reaching here well
            })    
      })
    

    From the Docs:

    $q.when

    Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. This is useful when you are dealing with an object that might or might not be a promise, or if the promise comes from a source that can't be trusted.

    For more information, see