简体   繁体   中英

Passing object between controllers in Angularjs

I'm new to angular and am struggling to get to understand how to use a Service to pass data from one controller to another.

So far with with Angular, I have been able to understand how to call controllers and pass data to them from within HTML. That's been especially fine in order to set up a Map Controller, whereby I look through a list of results that comes from PHP, and send data from those results into my controller, to create markers on a map.

What has me completely stumped, is having one controller that generates a nested object via a ElasticSearch call and then passing that data to my Map Controller.

Initially I tried looping through the results via ng-repeat, and while I was able to output the results, my MapController wasn't able to read those results in the HTML as they were within the confines of my IndexController (which was outputting the data). Well I assume that was the case.

This is what I tried, and while it outputted the data, I could never read it in MapController.

<div ng-controller="IndexController">
    <div ng-repeat="r in listingsArea.results">
        <div class="component home-listings"
            data-id="{{r.id}}"
            data-url="{{r.url}}"
            data-lat="{{r.lat}}"
            data-lng="{{r.lon}}"
            data-address="{{r.address}}"
            data-price="{{r.price}}"
        ></div>
    </div>
</div>

I've read that the best way to pass data from one controller to another is via a service. I've followed a lot of documentation here, but despite this I am obviously missing something as it is not working.

This is what I have thus far:

ResultsService.js

App.factory("resultsService", function() {

var loadListingsArea = {};

return {
    getLocations: function() {
        return loadListingsArea
    },

    setLocations: function(loc) {
        loadListingsArea = loc;

IndexController.js

App.controller('IndexController', function($scope, resultsService) {

$scope.listingsArea = [];

$scope.loadListingsArea = function() {
    $http.get($window.location + '/listingsarea')
        .success(function(data) {
            $scope.listingsArea = data;
        }
    );
}

$scope.$watch(function() {
    return $scope.loadListingsArea;
}, function() {
    resultsService.setLocations($scope.loadListingsArea);
});
});

MapController.js (just trying to dump the object at this stage, not including my very long code base for the google map)

App.controller('MapController', function($scope, resultsService) {

$scope.locations = resultsService.getLocations();

alert($scope.locations);

This is a sample of what my object looks like when dumped from indexcontroller.js

{"count":4,
"results":[
      {"id":"1153292",
       "url":"/this-is-my-slug/1153292",
       "lat":"-37.822034",
       "lon":"144.969553",
       "address":"1302/430 Place Road",
       "price":"$2,350,000",
       "hero":"some-image-here.jpg"}
]};

The $http service returns a promise. Store that. No need to do the $q.defer stuff.

App.factory("resultsService", function() {

  var self = this;
  self.listingsPromise = undefined;

  return {
      loadLocations: function(url) {
           self.listingPromise = $http.get(url);
           return self.listingPromise;
      },
      getLocations: function() {
        return self.listingPromise;
      }
  );
}

The controller that initiates the retrieve can do this:

resultsService.loadLocations() // returns a promise
  .then(function(response){
    $scope.listingsArea = response.data;
  }) .catch ( function (error) {
    throw error;
  });

And the controller that just needs to get it can do this:

resultsService.getLocations()
  .then(function(response){
    $scope.listingsArea = response.data;
  }) .catch ( function(error) {
    throw error;
  });

Notice that both controllers need to check for errors.

Also notice that .then returns data differently than .success .

The AngularJS team has come to their senses and deprecated .success . We all should be using .then from now on.

For information on the deprecation of .success and more info see the latest AngularJS $http API Docs

Move the $http.get into a function in your service. Edited to use $q.deferred instead of returning the $http's promise.

App.factory("resultsService", function() {

  var self = this;
  self.deferred = $q.defer();
  self.listingsArea = {};

  return {
      loadLocations: function() {
          $http.get($window.location + '/listingsarea')
              .then(function(data){
                 self.listingsArea = data;
                 self.deferred.resolve(self.listingsArea);
              },
              function(e){
                self.deferred.reject(e);
              });
          return self.deferred.promise;
      },
      getLocations: function() {
        return self.deferred.promise;
      }
  );
}

The controller that initiates the retrieve can do this:

resultsService.loadLocations() // returns a promise
  .then(function(data){
    $scope.listingsArea = data;
  });

And the controller that just needs to get it can do this:

resultsService.getLocations()
  .then(function(data){
    $scope.listingsArea = data;
  });

This may require some extra massaging but it should give you a direction to head in.

Also note that sharing the object this way means you can edit the same object from either controller. To avoid this, pass around an angular.copy of the data object instead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM