v_i_m
v_i_m

Reputation: 171

AngularJS: share the data of the same controller in two different, not nested parts of the page

I want to share the data of one controller between two places in my page. For example:

<div ng-app="myApp">
    <div ng-controller="myController">
        <input type="text" ng-model="x" /> {{x}}
    </div>
</div>
<!-- these are in totally different places and I do not want, nor can't nest them -->
<div ng-app="myApp">
    <div ng-controller="myController">
        <input type="text" ng-model="x" /> {{x}}
    </div>
</div>

and of course, this:

var myApp = angular.module('myApp', []);
myApp.controller('myController', function($scope) {
    $scope.x = 'test';
});

What can I do so that, no matter what I type first input text will be reflected in the second? And vice versa? Basically the same data being propagated to these two sections, while maintaining a single copy of the data.

JSFiddle here: http://jsfiddle.net/LETAd/

PS: I bootstrap it manually, if this is of any relevance.

Thanks!

Upvotes: 6

Views: 17839

Answers (2)

Umur Kontacı
Umur Kontacı

Reputation: 35478

Ideally, you should have only one application running in a single page. Since you also need to communicate between the controllers, you should really run a single application. Possibly on body or html. Then you can create a main controller which would encapsulate all your controllers. (controller inheritance).

Here is what it should look like:

<html ng-app="myApp">
  <head>...</head>
  <body ng-controller="MainCtrl">
    <div ng-controller="MyCtrl">
      <input type="text" ng-model="mainView.x" /> {{x}}
    </div>
    <div ng-controller="MyCtrl">
      <input type="text" ng-model="mainView.x" /> {{x}}
    </div> 
  </body>

And JS:

function MainCtrl($scope) {
  $scope.mainView = {};
}
function MyCtrl($scope) {

}

We created a mainView object on the MainController, and since MyController and its scope prototypally inherit from MainController we can reach that.
There is one caveat you should be aware of, when you use ngModel, it is almost always best to have a dot in somewhere (paraphrased from angularjs's authors).

Due to javascript's prototypal inheritance:

// In MainCtrl
$scope.mainView.x = "hello";
$scope.myX = "hello";

// In MyCtrl
$scope.mainView.x
>> "hello"
$scope.myX
>> "hello"
$scope.mainView.x = "welcome";
$scope.myX = "welcome";

// In MainCtrl
$scope.mainView.x
>> "welcome"
$scope.myX
>> "hello"

When you ask for a property in an object in javascript, it looks its properties to see if there is one, if not, it goes up in the prototype chain (parent), and looks for it there, it goes up until it finds any or goes at the end of the prototype chain.

So when we set $scope.myX, we don't actually change myX in the parent scope but we create a property called myX in the current scope; because of the hiearchy in the prototype. However, when we set $scope.mainView.x, we first ask for mainView then set x which then results in changing the value in parent scope.

I know it feels kind of unrelated to the original question but surely one would suffer from this when one goes into controller and scope inheritance.

Upvotes: 3

Mark Rajcok
Mark Rajcok

Reputation: 364697

To share data between controllers, normally a service is your best option. Put the shared data into the service, and inject the service into the controller:

function myController($scope, MyService) {

Each scope/controller instance will then be able to access the shared data.

Note that services are singletons, so there will only be one instance of your shared data around.

Here is a fiddle (I didn't write it) showing how two controllers can share data.

See also AngularJS: How can I pass variables between controllers? and
Angularjs: two way data bindings and controller reload.

Upvotes: 4

Related Questions