I'm trying to share data across controllers. Use-case is a multi-step form, data entered in one input is later used in multiple display locations outside the original controller. Code below and in jsfiddle here.
HTML
<div ng-controller="FirstCtrl"> <input type="text" ng-model="FirstName"><!-- Input entered here --> <br>Input is : <strong>{{FirstName}}</strong><!-- Successfully updates here --> </div> <hr> <div ng-controller="SecondCtrl"> Input should also be here: {{FirstName}}<!-- How do I automatically updated it here? --> </div>
JS
// declare the app with no dependencies var myApp = angular.module('myApp', []); // make a factory to share data between controllers myApp.factory('Data', function(){ // I know this doesn't work, but what will? var FirstName = ''; return FirstName; }); // Step 1 Controller myApp.controller('FirstCtrl', function( $scope, Data ){ }); // Step 2 Controller myApp.controller('SecondCtrl', function( $scope, Data ){ $scope.FirstName = Data.FirstName; });
Any help is greatly appreciated.
Approach: To share data between the controllers in AngularJS we have two main cases: Share data between parent and child: Here, the sharing of data can be done simply by using controller inheritance as the scope of a child controller inherits from the scope of the parent controller.
14) Which of the following is used to share data between controller and view in AngularJS? Answer: B: "using services" is the correct answer.
A simple solution is to have your factory return an object and let your controllers work with a reference to the same object:
JS:
// declare the app with no dependencies var myApp = angular.module('myApp', []); // Create the factory that share the Fact myApp.factory('Fact', function(){ return { Field: '' }; }); // Two controllers sharing an object that has a string in it myApp.controller('FirstCtrl', function( $scope, Fact ){ $scope.Alpha = Fact; }); myApp.controller('SecondCtrl', function( $scope, Fact ){ $scope.Beta = Fact; });
HTML:
<div ng-controller="FirstCtrl"> <input type="text" ng-model="Alpha.Field"> First {{Alpha.Field}} </div> <div ng-controller="SecondCtrl"> <input type="text" ng-model="Beta.Field"> Second {{Beta.Field}} </div>
Demo: http://jsfiddle.net/HEdJF/
When applications get larger, more complex and harder to test you might not want to expose the entire object from the factory this way, but instead give limited access for example via getters and setters:
myApp.factory('Data', function () { var data = { FirstName: '' }; return { getFirstName: function () { return data.FirstName; }, setFirstName: function (firstName) { data.FirstName = firstName; } }; });
With this approach it is up to the consuming controllers to update the factory with new values, and to watch for changes to get them:
myApp.controller('FirstCtrl', function ($scope, Data) { $scope.firstName = ''; $scope.$watch('firstName', function (newValue, oldValue) { if (newValue !== oldValue) Data.setFirstName(newValue); }); }); myApp.controller('SecondCtrl', function ($scope, Data) { $scope.$watch(function () { return Data.getFirstName(); }, function (newValue, oldValue) { if (newValue !== oldValue) $scope.firstName = newValue; }); });
HTML:
<div ng-controller="FirstCtrl"> <input type="text" ng-model="firstName"> <br>Input is : <strong>{{firstName}}</strong> </div> <hr> <div ng-controller="SecondCtrl"> Input should also be here: {{firstName}} </div>
Demo: http://jsfiddle.net/27mk1n1o/
I prefer not to use $watch
for this. Instead of assigning the entire service to a controller's scope you can assign just the data.
JS:
var myApp = angular.module('myApp', []); myApp.factory('MyService', function(){ return { data: { firstName: '', lastName: '' } // Other methods or objects can go here }; }); myApp.controller('FirstCtrl', function($scope, MyService){ $scope.data = MyService.data; }); myApp.controller('SecondCtrl', function($scope, MyService){ $scope.data = MyService.data; });
HTML:
<div ng-controller="FirstCtrl"> <input type="text" ng-model="data.firstName"> <br>Input is : <strong>{{data.firstName}}</strong> </div> <hr> <div ng-controller="SecondCtrl"> Input should also be here: {{data.firstName}} </div>
Alternatively you can update the service data with a direct method.
JS:
// A new factory with an update method myApp.factory('MyService', function(){ return { data: { firstName: '', lastName: '' }, update: function(first, last) { // Improve this method as needed this.data.firstName = first; this.data.lastName = last; } }; }); // Your controller can use the service's update method myApp.controller('SecondCtrl', function($scope, MyService){ $scope.data = MyService.data; $scope.updateData = function(first, last) { MyService.update(first, last); } });
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