1

I have a controller which is fetching an XML file using $http and parsing it into a json object. This is 'MainCtrl'. Now I want to get the same json object in other controllers without again going through an $http because I have already loaded the XML.

Here is my first controller

angularXML.controller('MainCtrl', ['$scope', '$http','courseDefService', function($scope, $http, courseDefService) {
    $http.get(base_url + 'assets/js/angularxml/courseDef.xml').then(function(response) {
    var chapters = [];
    var courseDef = x2js.xml_str2json(response.data);
    console.log(courseDef);
}

And here is my second controller

angularXML.controller('chapterCtrl', ['$scope', '$routeParams', function($scope, $routeParams) {
$scope.chapterNumber = $routeParams.id;
var chapter = $scope.chapterNumber - 1; /* index starts from zero */
}

I think I need to use factory. But I am not sure how to do that. I tried one implementation where I was fetching the XML inside the factory. But when I was calling the factory method, it was doing another ajax request which I confirmed through console.

Please help.

Amitav Roy
  • 741
  • 1
  • 11
  • 21
  • possible duplicate of [How can I pass variables between controllers in AngularJS?](http://stackoverflow.com/questions/12008908/how-can-i-pass-variables-between-controllers-in-angularjs) – zs2020 Aug 09 '13 at 14:45

3 Answers3

5

What about creating some kind of a message bus in your app?

First, create a MessageBus service:

module.factory("MessageBus", function($rootScope) {
    return {
        broadcast : function(event, data) {
            $rootScope.$broadcast(event, data);
        }
    };
});

Then, inject it to the originator controller:

function OriginatorController($scope, MessageBus) {
    $scope.funct = function(e) {
        // get data
        MessageBus.broadcast("data", data);
    };
};

And subscribe to events anywhere you want:

$scope.$on("data", function(arguments) {
    console.log(arguments);
});

You can even use $rootScope directly via DI and call $broadcast on it in your controllers, but creating a service is more expressive.

EDIT: Here is a pen for you.

madhead
  • 31,729
  • 16
  • 153
  • 201
3

Here is another quick and dirty approach: http://jsfiddle.net/cAY2N/

Basically, each controller has a reference to some variables in a service. Whenever the serivce's data changes, the changes are reflected automatically in all the controllers.

var app = angular.module('centralizedData', []);

app.service('CentralService', function($q, $timeout) {
    var self  = this,
        count = 0
        ;

    this.centralData = {};

    this.getData = function() {
        $timeout(function() {
            self.centralData.message = 'Hello: ' + count++;
        });
    };
});

app.controller('FirstController', function($scope, CentralService) { 
    $scope.data = CentralService.centralData;   
    CentralService.getData();
});

app.controller('SecondController', function($scope, CentralService) {
    $scope.data = CentralService.centralData;
    setTimeout(CentralService.getData, 2000);
});
Scott
  • 2,557
  • 5
  • 26
  • 32
  • Somehow I am not able to get this to work. Here is a fiddle for the same. Reminding you again that I am trying to load an XML file inside the first controller and then use the same in second. http://jsfiddle.net/Nv779/ – Amitav Roy Aug 09 '13 at 16:00
  • In that fiddle you are still making independent ajax calls in each controller, and you aren't assigning any $scope variables to the "courseDef" object in your CentralCourseDef service. So when "getXML" is called in your CentralCourseDev service, your controllers have no idea that that happened. You will have to plug it up like my jsFiddle by bringing in the service as a dependency in each controller, and then making some assignments. The $rootScope approach by madhead may work better in your case thoough. – Scott Aug 09 '13 at 17:23
2

Its not a best practice to make the XHR call within the controller. Separate it out in a factory and take care not to repeate the call If you have data available. Your service should have a full control over when to hit the server to fetch data. Controllers should only access the service.

I would probably do this:

App.factory('eywa', ['$http', function($http) {
  var eywaFactory = {};

  eywaFactory.data = '';
  eywaFactory.load = function() {
    this.data = $http.get('./assets/js/angularxml/courseDef.xml').then(function(data) {
      return x2js.xml_str2json(data);
    });
    return this.data;
  };

  eywaFactory.get = function() {
    return this.data === '' ? this.load() : this.data;
  };

  return eywaFactory;
}]);

And call the service inside controller:

App.controller('MainCtrl', function($scope, eywa) { 
    eywa.get().then(function(data) {
      $scope.courseDef = data;
    });
});
codef0rmer
  • 10,284
  • 9
  • 53
  • 76