Updating a factory property not being reflected in the controller scope

I am new to ionic and angular but have so far found it fun the try. I have a problem however. I have created a factory with a method and also some properties. If I update the property then the UI is not updating even though the $scope is set to the factory property in the controller. When the I run the app the value stays as false even though it is being set to true.

.controller('PlaylistsCtrl', function ($scope, $timeout, accountFactory) {
    $scope.accounts = accountFactory.accountsProp;
    $scope.valueLoaded = accountFactory.valueLoadedProp;
})

.factory('accountFactory', function () {
    var accounts = [
            { id: 1, title: 'tetst1' },
            { id: 2, title: 'tetst2' },
            { id: 3, title: 'tetst3' }
        ],
        accountsDetailed = [],
        valueLoaded = false;

    function populateAccountObjects() {
        var sequence = Promise.resolve();
        accounts.forEach(function (account) {
            sequence = sequence.then(function () {
                return account;
            }).then(function (acc) {
                valueLoaded = true;
                console.log('loaded ' + acc.id);
            });
        });
    }

    var prom = new Promise(function (resolve, reject) {
        window.setTimeout(function () {
            populateAccountObjects();
            resolve();
        }, 5000);
    });

    return {
        accountsProp: accounts,
        accountsDetailedProp: accountsDetailed,
        valueLoadedProp: valueLoaded
    };
});

I have removed most of the code in the method and left the code above with least amount possible.

The outcome I am expecting is for the view to load with the list and the $scope.valueLoaded to be false in the UI (this is happening). But after 5 seconds the value is being set to ‘true’ and so I would expect the UI to change to true.

Can anyone spot what I have done wrong here?

Even if I simplify the factory to the code below the UI still only shows ‘before’ and never changes to ‘after’ even though the two logs show ‘before’ and then ‘after’

.factory('accountFactory', function () {
    var valueLoaded = 'before';

    function populateAccountObjects() {
        valueLoaded = 'after';
        return;
    }

    var prom = new Promise(function (resolve, reject) {
        window.setTimeout(function () {
            console.log(valueLoaded);
            populateAccountObjects();
            console.log(valueLoaded);
            resolve();
        }, 5000);
    });

    return {
        valueLoadedProp: valueLoaded
    };
});

Welcome to the worldof async programming! :slight_smile:
When you run your’s PlaylistsCtrl it creates the instance of accountFactory and get values from it, and they a preseted to before, when the accountFactory is started it also starts to do some timeout work - populateAccountObjects func, which rewrite valueLoaded but this happens after you’ve read it.

Btw I recommend you to use $q service for async.

1 Like

i do not tested it, but it should be something like this:

.factory('accountFactory', ['$timeout', '$q', function ($timeout, $q) {
  var valueLoaded = 'before',
      deferred = $q.defer(); // new deferred object

  $timeout(function () { // simulate timeout in angularjs context
    valueLoaded = 'after'; // set value
    deferred.resolve(valueLoaded); //resolve promise with current valueLoaded
  }, 2000);

  return {
    valueLoadedProp: deferred.promise // return promise object
  };
}]);

.controller('PlaylistsCtrl', function ($scope, accountFactory) {
    accountFactory.valueLoadedProp.then(function (valueLoaded) {
      // success case of the promise
    }, function () {
      // error case --> deferred.reject() has been called
    )).finally(function () {
      // do something even if it is error or success case
    });
})