Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Share data between AngularJS controllers

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.

like image 422
johnkeese Avatar asked Feb 20 '14 21:02

johnkeese


People also ask

How can we share the data between controllers in AngularJS?

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.

Is used to share data between controller and view in AngularJS?

14) Which of the following is used to share data between controller and view in AngularJS? Answer: B: "using services" is the correct answer.


2 Answers

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/

like image 138
tasseKATT Avatar answered Oct 13 '22 00:10

tasseKATT


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);    } }); 
like image 31
bennick Avatar answered Oct 12 '22 22:10

bennick