2

I have an AngularJs app with a master details that I have changed to use ui-router.

Previously, I had a SelectionService with a plain JavaScript observer that was used by the master to notify selection and by the details to update himself. The selection was just a technical identifier, so that the DetailsController has to get the item from my BackendService which is basically a local cache.

Now with ui-router when an item is selected into the master, I go the details state and the same flow remains (use the technical id to get details from backend).

My problem is that into the previous version all updates made on the details where automagically updated on the master. But that is broken with the ui-router version, probably because the MasterController and DetailsController don't share the same scope.

So, my question is : How do you ensure that a list of items is updated when one item is changed. Do you rely on some AngularJs functionalities (then how) or do you use a classic events mechanism with $scope.$broadcast and $scope.$on ?

Edit, after more investigations

I have read some articles that are clearly against the usage of AngularJs events ($scope.$broadcast, $scope.$emit and $scope.$on) and recommand a custom event bus/aggregator. But I would like to avoid that and thus rely on the AngularJs digest lifecycle. However what is suggest by @Kashif ali below is what I have but my master is not updated when the details changes.

angular
    .module('masterDetails')
    .service('BackendService', function($q){
        var cache = undefined;
        var Service = {}
        Service.GetImages = function() {
            var deferred = $q.defer();
            var promise = deferred.promise;
            if ( !cache ) {
                // HTTP GET from server .then(function(response){
                    cache = JSON.parse(response.data);
                    deferred.resolve(cache);
                });   
            } else {
                deferred.resolve(cache);
            }
            return promise;
        }
        Service.GetImage = function(key) {
            return GetImages().then(function(images){
                return images[key];
            });
        }
        Service.SetImage = function(key, updated) {
            GetImages().then(function(images){
                images[key] = updated;
                // TODO; HTTP PUT to server
            });
        }
    })
    .controller('MasterController', function(BackendService){
        var vm = this;
        vm.items = [];
        vm.onSelect = onSelect;

        init();

        function init() {
            BackendService.GetImages().then(function(images){
                // images is a map of { key:String -> Image:Object }
                vm.items = Object.keys(images).map(function(key){
                    return images[key];
                });
            });
        }

        function onSelect(image) {
            $state.go('state.to.details', {key: image.key});
        }
    })
    .controller('DetailsController', function(BackendService, $stateParams){
        var vm = this;
        vm.image = undefined;

        init();

        function init() {
            BackendService.GetImage($stateParams.key).then(function(image){
                vm.image = image;
            }).then(function(){
                // required to trigger update on the BackendService
                $scope.$watch('[vm.image.title, vm.image.tags]', function(newVal, oldVal){
                    BackendService.SetImage(vm.image.key, vm.image);
                }, true);
            });
        }
    });

Edit, this is due to the states

So, when I open the app on #/images the images state start. Then I select one image to go to the images.edit state and everything works well, the master is updated when details changes.

However if I start on #/images/:key which is the images.edit state, then the master ignore all changes mades on the master.

gervais.b
  • 2,294
  • 2
  • 22
  • 46

1 Answers1

0

You can rely on both the solution you have mentioned

1.You can achieve this using factories in angularjs

Factories/services are the singleton objects that is shared along the the app: example:

    angular.module("app",[]).factory('myfactory',function(){
var data;
{
getData:getData,
setData:setData
};
function setData(data1)
{
data=data1;
}
function getData()
{
return data;
}
}
).controller('myclrl1',function($scope,myfactory){

}).controller('myclrl2',function($scope,myfactory){

});

you can inject these controller in different views and can access singleton factory(all controller will share the same object) "myfactory" in both controller using getter and setter

  1. you can use $scope.$broadcast and $scope.$on to make nested contollers to communicate with each other

you can find the detailed Example over here.

$scope.$broadcast and $scope.$on

hope that would be helpful

Regards

Community
  • 1
  • 1
Kashif ali
  • 139
  • 1
  • 6