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
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.
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 .
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.
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; });
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With