ajmajmajma
ajmajmajma

Reputation: 14226

Angular, setting up a callback function for updating between factory and controller

I'm not sure if i have completely wrapped my head around this idea - but I'll try my best to clearly describe what I am trying to do here.

I have a factory that changes and parses a URL for me, so I can pass params into a controller for use (that were stored in the url). This is sort of so I can save a state for the user and they can share it via copy'ing of a URL (send it to their friends or bookmark it or w/e).

I am trying to set up a factory (or service) that listens for locationChangeSuccess - so that if the user mofies the url and presses enter, it will refresh the scopes in the controllers. So here is what I have:

   .factory("urlFactory", function($location, freshUrl, StateString){
     //request to change new url
    requestObj.requestState = function(moduleName, stateName, startVar){

    }

    //request item from url, via your module and state name
    requestObj.parseState = function(moduleName, stateName){

   }

I dropped the center out (if it is needed im happy to link), but those just get and set the url for me.

So in the controllers I do something like

 $scope.mod2m3 = urlFactory.parseState("module2", "mod3");
$scope.mod2m4 = urlFactory.parseState("module2", "mod4");

So when they land on the page, they pull their state. This works great. However, now i'm trying to solve some edge case scenarios where maybe the user modifies the url.

So I can latch onto that even pretty easily with

 .factory("urlWatcher", function($location, $scope){
    var urlWatcher = {};
     $scope.$on('$locationChangeSuccess', function(event) {
            console.log("Asdsa");
       });

     return urlWatcher
});

However, where I am struggling is trying to determine a way where when this fires, it would connect the new value to the scope in the controller. It was suggested to me that a callback of some sort in the parse (set) function, but I am struggling with how to approach that. It would be super cool if I could set a way for this factory/service to re send the new value when it changes to the right place. Callback sounds good, however I don't know how to config this correct.

The easiest route would be to just do an

 $scope.$on('$locationChangeSuccess', function(event) {
            console.log("Asdsa");
       });

In each controller and manually bind to each scope, but I am trying to make this as modular as possible (and thats also a ton of watchers on the locationchangesuccess). would be fantastic if I could figuire out a clean way to set the service/factory to listen once, and on change find the right module/controller and change the value.

I can't seem to think a clear route, so I would be very greatful for any insight to this issue. Thank you very much for reading!

Upvotes: 1

Views: 514

Answers (2)

Eyal
Eyal

Reputation: 532

You can assign a variable in the scope to an object in the factory, that way it's bound to a reference instead of a value. Then, in your HTML you bind the reference to the DOM. urlFactory.parseState() should then save the result to said object, and return the key where it was saved.
For example:
In urlFactory:

requestObj.parseState = function(moduleName, stateName){
var key = moduleName+stateName;
this.urlContainer[key] = "www.example.com";
return key;

   }

In the controller:

$scope.urls = urlFactory.urlContainer;
$scope.mod2m3 = urlFactory.parseState("module2", "mod3");

In your HTML:

{{urls[mod2m3]}}

This way, "urls" is bound to a reference, which angular watches for changes, and whenever you change urls[mod2m3], it will affect the DOM.
You can also just react to changes in the scope variables by watching them:

 $scope.$watch('urls', function() {
       //do something
   });

NOTE: Since this is an object, you might need to use $watchCollection instead of $watch.

Upvotes: 0

Valentin Waeselynck
Valentin Waeselynck

Reputation: 6061

If what you want is a publish/subscribe architecture, where publications are global and subscriptions have the same lifecycles as Angular scopes... then Angular events are what you're looking for. There's no point setting up an ad hoc communication system with callbacks and whatnut, that would just be partially reinventing events.

However, if you want to make the semantics more obvious / add flexibility, you can listen once to $locationChangeSuccess in a service and broadcast a custom event.

$rootScope.$on("$locationChangeSuccess", function (event) {
  $rootScope.$broadcast('myCustomeEvent', {message: "Guys, time to refresh!"});
});

Then listen to this event in each of the scopes where it is relevant.

$scope.$on('myCustomeEvent', function (event) {
  console.log("Asdsa");
});

If setting up the listening gets repetitive, by all means, factor it out in a function, which you can for example put in a service:

myApp.factory('someFactory', [function () {
  return {
    listenToLogAsdsa: function (scope) {
      scope.$on('myCustomeEvent', function (event) {
        console.log("Asdsa");
      });
    }  
  };
}]);

Then all you have to write in your controller is:

someFactory.listenToLogAsdsa($scope);

Upvotes: 3

Related Questions