Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Share a single service between multiple angular.js apps

I'm building an ecommerce site (based on shopify) and I'm using multiple small angularjs apps to handle things such as a quick shopping cart, wishlists, filtering products and a few other smaller items. I initially used one big application (that had routing and everything), but it was a bit to restrictive when I didn't have a full REST API.

There are a couple of services that I would like to share between the angular apps (the cart service, so I can have a quick add button that will reflect in the mini-cart and such), but I'm not sure of the best way (if there is a way) to go about this. Just sharing a module with the service doesn't keep the same state across the apps.

I tried my hand at it, but I it doesn't seem to update state between both apps. The following is the javascript I tried using. It's also on jsfiddle with accompanying html: http://jsfiddle.net/k9KM7/1/

angular.module('test-service', [])   .service('TestService', function($window){     var text = 'Initial state';      if (!!$window.sharedService){       return $window.sharedService;     }      $window.sharedService = {       change: function(newText){         text = newText;       },       get: function(){         return text;       }     }      return $window.sharedService;   });  angular.module('app1', ['test-service'])   .controller('App1Ctrl', function($scope, TestService){     $scope.text = function(){ return TestService.get() }     $scope.change = function(){ TestService.change('app 1 activated') }   });  angular.module('app2', ['test-service'])   .controller('App2Ctrl', function($scope, TestService){     $scope.text = function(){ return TestService.get() }     $scope.change = function(){ TestService.change('app 2 activated') }   });  var app1El = document.getElementById('app1'); var app2El = document.getElementById('app2');  angular.bootstrap(app1El, ['app1', 'test-service']); angular.bootstrap(app2El, ['app2', 'test-service']); 

Any help would be appreciated

like image 284
Tom Brunoli Avatar asked May 23 '13 23:05

Tom Brunoli


People also ask

Can there be two ng app for a single angular application?

Only one ngApp directive can be auto-bootloaded per HTML Document but you can have multiple apps as long as you manually bootstrap the subsequent ones.

Can angular applications ng app be nested within each other?

AngularJS applications cannot be nested within each other. Do not use a directive that uses transclusion on the same element as ngApp . This includes directives such as ngIf , ngInclude and ngView .

Can we have two controllers in AngularJS?

An AngularJS application can contain one or more controllers as needed, in real application a good approach is to create a new controller for every significant view within the application.


2 Answers

The sharedService is being shared, but one angular app doesn't know that something updated in the other app so it doesn't kick off a $digest. You have to manually tell the $rootScope of each application to start a $digest by calling $rootscope.$apply()

Fiddle: http://jsfiddle.net/pvtpenguin/k9KM7/3/

  angular.module('test-service', [])   .service('TestService', function($rootScope, $window){     var text = 'Initial state';     $window.rootScopes = $window.rootScopes || [];     $window.rootScopes.push($rootScope);      if (!!$window.sharedService){       return $window.sharedService;     }      $window.sharedService = {       change: function(newText){         text = newText;         angular.forEach($window.rootScopes, function(scope) {           if(!scope.$$phase) {               scope.$apply();           }         });       },       get: function(){         return text;       }     }      return $window.sharedService;   }); 
like image 56
Matt York Avatar answered Sep 21 '22 12:09

Matt York


I was trying to solve a similar problem. Sharing factories between apps running in different iFrames. I wanted any $apply() in any frame to cause a digest cycle in all other frames. Allowing simple ng-clicks bound directly to a factory method to update the view in all other frames. I created a module which handles the binding of scopes and sharing of factories:

Click here to see plunkr

Just include the module on each app:

angular.module('App', ['iFrameBind']) 

And change any factory's return statement to return the shared version of that factory:

return sharedFactory.register('counter', service); 

e.g.

.factory('counter', function (sharedFactory) {    var service;   var val = 0;    function inc() {     val++;   }    function dec() {     val--;   }    function value() {     return val;   }    service = {     inc: inc,     dec: dec,     value: value   };    return sharedFactory.register('counter', service); })  .directive('counter', function (counter) {   return {     template: '{{counter.value()}} ' +               '<button ng-click="counter.inc()">Up</button> ' +               '<button ng-click="counter.dec()">Down</button> ',     restrict: 'E',     link: function postLink(scope) {       scope.counter = counter;     }   }; }); 

Counter updates in both frames when click happens in either

like image 24
Phil Holden Avatar answered Sep 23 '22 12:09

Phil Holden