Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angular sharing data between controllers: service vs event

Are there any general rules of thumb for sharing data between controllers?

I've seen 2 types of answers to how to accomplish this:

  1. Inject a service into both controllers that will contain the shared data
  2. Use $scope.$broadcast('someEvent', sharedArg) and $scope.$on('someEvent', sharedArg)

I'm not sure when it is best to use one approach over the other.

Moreover, there is 1 thing I really don't like about approach #1. Here is a toy-example taken from some real code:

angular.module('profileService', [])
       .factory('profileService', 
  [  
    function() {
      var selectedProfile = { profileId: null };

      return {
        getProfile: function(profileId, callback) {
          // marshall ajax request into format server will know how to handle
          // ajax call to server
          // marshall ajax response into format UI (controller) will know how to handle
        },

        createProfile: function(callback) { ... // ajax call to server ... },
        updateProfile: function(callback) { ... // ajax call to server ... },
        deleteProfile: function(callback) { ... // ajax call to server ... },

        getSelectedProfile: function() {
          return selectedProfile.profileId;
        },

        setSelectedProfile: function(profileId) {
          selectedProfile.profileId = profileId;
        },
      };
    }
  ]);

This seems to be poor design. The service (as is most of our services) exists to translate and make requests to/from the server. Most of our services are completely stateless. It is trivial to inject mock services for testing, etc...

But now all of a sudden our service has state. This just seems like a bad idea.

An alternative approach might be to build a service that exists solely for sharing data between controllers (and never makes backend calls), but this isn't all the appetizing either. It smells like a service providing a global namespace which doesn't seem like great design.

Just wondering, are there any thoughts about approach #1 vs #2. Is containing state in a service not necessarily a bad thing? Are events a better approach to sharing state?

Thanks.

like image 555
lostdorje Avatar asked Oct 20 '22 11:10

lostdorje


2 Answers

The official AngularJS guide for controllers recommends the use of services for sharing state:

Do not use controllers to:

  • Share code or state across controllers — Use angular services instead.
like image 50
Tyler Eich Avatar answered Oct 23 '22 01:10

Tyler Eich


Using services to share data/state is fine (webcam.isStreaming, socket.isConnected, etc), but things like the "selection" don't belong in the profileService, it should for example be possible to have multiple selections.

Events are not for sharing state, they are for ... events. like "includeContentLoaded", "webcamReady", "socketMessage", etc. A controller might not be ready (loaded async via ng-include) and miss an event.

Method 3: Have you tried the UI Router yet? it is organized around states.
You can use $stateParams or resolve to pass the selected profile.
Some of it is also possible with ngRoute, but very limited.

Method 4: You can use the $scope to share data between parent and child controllers.
A benefit/downside is that selection lifetime is connected to the scope.
This creates some coupling/complexity, but not more than a profileSelectionsService would.
Works great if the parent controllers writes to the $scope and child controller reads. It gets tricky when both controllers want to write to the $scope

like image 22
Bob Fanger Avatar answered Oct 23 '22 02:10

Bob Fanger