2

I want multiple controllers to be able to update a single view attached to one controller using a factory with $http.

My list view:

<div class="list" ng-repeat="image in images" ng-controller="controller1">
   <div lass="item"><img src="{{image.url}}" /></div>
</div>

Service:

.factory("imageService", function($http) {
  return {
    getImages: function() {
      return $http({
        method: "get",
        url: "http://example.com/images",
        params: { user: window.localStorage['user_id'] }
      })
    }
  }
});

Controller 1:

.controller('controller1', function($scope, imageService) {
   window.localStorage['user_id'] = '101';
   var handleSuccess = function(data, status) {
       $scope.images = data;
   };
   imageService.getImages().success(handleSuccess);
})

This all works. When the app is loaded, the list immediately is populated with a list of images for user '101'.

In another controller, I want to be able to switch users and automatically re-poupulate the image list in the view from controller 1 with new images.

Controller 2:

.controller('controller2', function($scope, imageService) {
   window.localStorage['user_id'] = '202';
   imageService.getImages();
})

So controller 2 will run getImages() and I can see the $http request working via chrome dev tools / XHR. And I know why the list view attached to controller1 is not populating, but I dont know how to make it populate. I have tried moving the success callback into the service and setting a 'images' property on the service and a $scope.images in controller1, but no luck there.

How can I force the new list of images into the view attached to controller 1?

lilbiscuit
  • 2,109
  • 6
  • 32
  • 53
  • You could emit an event from the rootScope to the controller and the listener for the emit handles loading the images from the imageService. – tafoo85 Aug 05 '15 at 14:40
  • @tafoo85 Is using $rootScope definitely required to get the image list updated? – lilbiscuit Aug 05 '15 at 14:48
  • Nah, it was off the top of my head quick two second solution. That other guy's idea is better. – tafoo85 Aug 05 '15 at 14:57

2 Answers2

3

You should just manage a list into your service that you will bind to your controller1 :

.factory("imageService", function($http) {
    var service = {};
    service.images = {};
    service.images.list = [];
    service.getImages = function(userId) {
      window.localStorage['user_id'] = userId;
      return $http({
        method: "get",
        url: "http://example.com/images",
        params: { user: userId }
      }).success(function(data){
          service.images.list = data
      });
    }

  //at the initialization of the service, you launch the getImages once with the localStorage value.
  service.getImages(window.localStorage['user_id']);

  return service;
});

Then you can bind it like this in your controllers :

.controller('controller1', function($scope, imageService) {
   $scope.images = imageService.images;
   //then access it in the view with images.list
   imageService.getImages(101);
})

.controller('controller2', function($scope, imageService) {
   $scope.images = imageService.images;
   //then access it in the view with images.list
   imageService.getImages(202);
})

Note that using a sub object (images.list instead of images) is important.

If you want some more precise informations about why this sub object is needed you can read this answer on this subject

Hope it helped.

Community
  • 1
  • 1
Okazari
  • 4,597
  • 1
  • 15
  • 27
  • So in the view, ng-repeat="image in images.list". This seems to work well. Let me test. – lilbiscuit Aug 05 '15 at 15:34
  • @lilbiscuit How is the integration doing ? Feel free to ask if you need some help. That's exactly how the ng-repeat will look like. – Okazari Aug 05 '15 at 16:49
  • @lilbiscuit Btw, why don't you use a var with your get function instead of using the local storage ? – Okazari Aug 05 '15 at 16:50
  • @Okazzari - I use localStorage to preserve the user selection (this is a mobile hybrid app). – lilbiscuit Aug 05 '15 at 16:56
  • @lilbiscuit i'm not sure i understood your question but you can manage the user_id local storage into the service. I'll update the answer to show how. – Okazari Aug 06 '15 at 14:52
0

I think you can just use one controller. At some time point, say, a user clicks some button, reload the image lists and re-render the view to show the list.

For example, make the factory like:

.factory("imageService", function($http) {
  return {
    getImages: function(userId) {
      return $http({
        method: "get",
        url: "http://example.com/images",
        params: { user: userId }
      });
    }
  };
});

And in the controller:

.controller('imageController', function($scope, imageService) {

   function refreshImages (userId) {
     imageService.getImages(userId).success(function(data) {
       $scope.$apply(function () {
         $scope.images = data;
       });
     });
   }

   refreshImages('101');
   $scope.loadImages = function (userId) {
     refreshImages(userId);
   };
});
Joy
  • 9,430
  • 11
  • 44
  • 95
  • I need to be able to update the list from within multiple controllers. – lilbiscuit Aug 05 '15 at 15:51
  • Well, if the two controllers shares the same scope, you need to call `$scope.$apply` after getting new list of images. – Joy Aug 05 '15 at 15:53
  • I still cannot imagine your scenario. Controllers should not share such kind of logic. You either extract to service/factory or directive. – Joy Aug 05 '15 at 15:53
  • The scenario is that each view in my app has its own controller. One view / controller displays the list of images. The other view/controller displays a list of users. Select a user in controller2 view, and see the resulting images for the selected user controller1 view. – lilbiscuit Aug 05 '15 at 16:46