6

I have inherited an angular app and now need to make a change.

As part of this change, some data needs to be set in one controller and then used from another. So I created a service and had one controller write data into it and one controller read data out of it.

angular.module('appRoot.controllers')

.controller('pageController', function (myApiService, myService) {
    // load data from API call
    var data = myApiService.getData();

    // Write data into service
    myService.addData(data);
})

.controller('pageSubController', function (myService) {
    // Read data from service
    var data = myService.getData();

    // Do something with data....
})

However, when I go to use data in pageSubController it is always undefined.

How can I make sure that pageController executes before pageSubController? Or is that even the right question to ask?

EDIT

My service code:

angular.module('appRoot.factories')

.factory('myService', function () {
    var data = [];

    var addData = function (d) {
        data = d;
    };

    var getData = function () {
        return data;
    };

    return {
        addData: addData,
        getData: getData
    };
})
3
  • 1
    Can we have a look at myService definition? Also your html Commented Nov 6, 2014 at 11:14
  • @RahilWazir added. usage of the data is actually in ng-table params Commented Nov 6, 2014 at 11:20
  • It would be great if you include your html so we will know how you have used the controllers. Commented Nov 6, 2014 at 11:23

2 Answers 2

6

If you want your controller to wait untill you get a response from the other controller. You can try using $broadcast option in angularjs.

In the pagecontroller, you have to broadcast your message "dataAdded" and in the pagesubcontroller you have to wait for the message using $scope.$on and then process "getData" function.

You can try something like this :

angular.module('appRoot.controllers')
.controller('pageController', function (myApiService, myService,$rootScope) {
    // load data from API call
    var data = myApiService.getData();

    // Write data into service
    myService.addData(data);
    $rootScope.$broadcast('dataAdded', data);
})

.controller('pageSubController', function (myService,$rootScope) {
    // Read data from service
    $scope.$on('dataAdded', function(event, data) {
        var data = myService.getData();
    }

    // Do something with data....
})
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks - I'll have a play with this and let you know
This was just what I needed - a global event which I can hook into. Thanks!
3

I would change your service to return a promise for the data. When asked, if the data has not been set, just return the promise. Later when the other controller sets the data, resolve the previous promises with the data. I've used this pattern to handle caching API results in a way such that the controllers don't know or care whether I fetched data from the API or just returned cached data. Something similar to this, although you may need to keep an array of pending promises that need to be resolved when the data does actually get set.

function MyService($http, $q, $timeout) {
  var factory = {};
  factory.get = function getItem(itemId) {
    if (!itemId) {
      throw new Error('itemId is required for MyService.get');
    }
    var deferred = $q.defer();
    if (factory.item && factory.item._id === itemId) {
      $timeout(function () {
        deferred.resolve(factory.item);
      }, 0);
    } else {
      $http.get('/api/items/' + itemId).then(function (resp) {
        factory.item = resp.data;
        deferred.resolve(factory.item);
      });
    }
    return deferred.promise;
  };

  return factory;
}

4 Comments

Thanks for your response - though I'm not making the api call from the service, just using it to store some data in. Is this not a recommended approach?
It doesn't seem OP sending any server-side request to retrieve the data. Its just a simple assignment of data to properties.
Am I missing something, or is your call to $timeout redundant? You should be able to just call deferred.resolve(factory.item) and return the promise.
It's pessimistic about releasing zalgo by sometimes having same-tick behavior and sometimes having future-tick semantics. This guarantees future-tick semantics 100% of the time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.