3

I have a factory and a Controller.

Factory

vm.profiles = new ProfileFactory();

Controller

if (Object.keys(vm.profiles.items).length == 0) {
      vm.noProfiles = true;
}

I have a prototype nextPage() in the ProfileFactory -> vm.profiles Object. This Method queries the backend. I want to set the vm.noProfiles Variable to true if there are no items in vm.profiles.items.

The Problem

It goes automatically inside the if statement, because the if doesn't wait until the item is populated through the prototype Method nextPage().

How can I force JavaScript to wait until it is populated? Is there a better solution?

//Edit

This ihere is part of the nextPage Method. Should I do the query in the controller and just return the promise from Restangular or $http?

// Get List of Posts
            Restangular.allUrl('user', ApiConfig.baseUrl + ':' + ApiConfig.port + '/users').getList(query)
                .then(function (items) {
                    //console.log(items);

                    if (items.length > 0) {
                        for (var i = 0; i < items.length; i++) {
                            this.items.push(items[i]);
                        }
                        if (this.offset < items.meta.page_count) {
                            this.offset += 1;
                        } else {
                            return;
                        }
                    }
                    this.busy = false;
                }.bind(this));
Simon Hagmann
  • 141
  • 1
  • 12
  • 3
    I think this is a good use case for using Promises (ES6 ones or $q by angularjs). Promise will trigger a callback once the server responded to your request. – Shikloshi Oct 21 '15 at 16:08
  • As @Shikloshi said you can check promises here because it's very good https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise – Endrit Shala Oct 21 '15 at 16:10
  • 1
    And just another thing - it is consider a good practice to return promise from the rest service back to the controller. – Shikloshi Oct 21 '15 at 16:20
  • @Shikloshi Should I do this without creating the object from the ProfileFactory, just call the rest service from the controller? – Simon Hagmann Oct 21 '15 at 16:35
  • Maybe you could just wait for items being loaded first? http://stackoverflow.com/questions/16286605/angularjs-initialize-service-with-asynchronous-data – Rainer Oct 21 '15 at 19:57
  • In case if you are lucky to be able to use ES6, `Object.observe(...)` might help you (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/observe). – John Doe Oct 30 '15 at 21:30

1 Answers1

0

If you are using the ui-router you can use it's resolve feature to specify what needs to be loaded before your controller ever becomes active.

There are two steps you need to take here:

  1. Set up resolve in your route configuration.

    In the rout configuration for your controller, add the resolve: key with a function returning a promise for the items you want pre loaded before your controller is activated. Something along the lines of:

    $stateProvider.state('myState', {
        // ...
        resolve: {
            items: function(Restangular, ApiConfig /* add any other di's here */) {
                return Restangular.allUrl('user', ApiConfig.baseUrl + ':' +
                                           ApiConfig.port + '/users');
       }
    

    Now when this route is fired, your controller is not loaded until the promise returned by the function under the items: key is resolved. The response from this promise is available to your controller, you just need to di it by:

  2. In your controller add the items to you di's in your controller definiton:

    angular
        .module('yourModuleName')
        .controller('YourControllerName', function(..., items) {
        // ...
        // items should hold the response from the promise returning function in 
        // route config
    });