10

I recently started using AngularJS and the way I'm building my apps now is like this:

MainController.js

var app = angular.module('app', ['SomeController', 'MainController']);

app.controller('MainController', function ($scope) {
    // do some stuff
}

SomeController.js

var SomeController= angular.module('SomeController', []);

SomeController.controller('SomeController', function ($scope) {
    $scope.variable = "test";
    // do some otherstuff
}

The problem that Im' running into is that the scope is not being shared between modules. From MainController I can't get the variable "test" for example.

  • What is the best practice for this? Do I store all my controllers in 1 module in 1 file?
  • How can i have 1 page with 2 controllers and share the $scope between them, or is it OK to put everything in just one controller ?
Chancho
  • 1,930
  • 2
  • 15
  • 20
  • 1
    This is definitely an X/Y problem. If you need to do something like this, you are doing something majorly wrong. Update your answer to explain what you actually are trying to accomplish. – m59 Dec 23 '13 at 21:11
  • 1
    Basically i'm asking how i should do this, i don't necessarily need to do it like this. – Chancho Dec 23 '13 at 21:15
  • See my answer, just be sure that you're packaging things together that belong together and not coupling things that shouldn't be coupled. – m59 Dec 23 '13 at 21:27

2 Answers2

20

You could use a service like this: Live demo here (click).

JavaScript:

var otherApp = angular.module('otherApp', []);
otherApp.factory('myService', function() {
  var myService = {
    someData: ''
  };
  return myService;
});
otherApp.controller('otherCtrl', function($scope, myService) {
  $scope.shared = myService;
});


var app = angular.module('myApp', ['otherApp']);

app.controller('myCtrl', function($scope, myService) {
  $scope.shared = myService; 
});

Markup:

  <div ng-controller="otherCtrl">
    <input ng-model="shared.someData" placeholder="Type here..">
  </div>
  <div ng-controller="myCtrl">
  {{shared.someData}}
  </div>

Here's a nice article on sharing data with services.

You can also nest controllers to have the parent controller's scope properties inherited by the child scope: http://jsbin.com/AgAYIVE/3/edit

  <div ng-controller="ctrl1">
    <span>ctrl1:</span>
    <input ng-model="foo" placeholder="Type here..">
    <div ng-controller="ctrl2">
      <span>ctrl2:</span>
      {{foo}}
    </div>
  </div>

But, the child won't update the parent - only the parent's properties update the child.

You would use "the dot rule" to have updates on the child affect the parent. That means nesting your properties in an object. Since the parent and child both have the same object, changes on that object will be reflected in both places. That's just how object references work. A lot of people consider it best practice to not use inheritance, but put everything in directives with isolated scope.

m59
  • 43,214
  • 14
  • 119
  • 136
  • Thanks for explaining, is it a common practice to have multiple modules on 1 page/or partial i should say ? i have the idea i'm doing it wrong. – Chancho Dec 23 '13 at 21:28
  • 1
    @Chancho You're not using multiple modules (and shouldn't be). You're using one module that has a dependency on another module. That sort of coupling is fine, but it seems like you're thinking of it incorrectly. Let's say that `Module A` is a sort of tool set you've created..maybe it has a service, directory and a controller that work together to provide a nice functionality. Now, you're creating an app, so you make `Module B`. You decide that `Module B` could use that functionality you made and packed in `Module A`, so `Module B` will have a dependency on `Module A`. – m59 Dec 23 '13 at 21:32
  • alright i think i get that now, but what about the controllers that reside in the modules. basically what i'm doing now is create a module with controller inside there. then in another controller i add the module as a dependency to that module. i think this is where i'm going the wrong way. - so to rephrase my question: how do i link multiple controllers with their scope together ? – Chancho Dec 23 '13 at 21:39
  • @Chancho In all likeliness, you really want the service solution, like I said. That is linking those scopes together, because they both reference the same object. Otherwise, their's scope inheritance, but it's limited. http://jsbin.com/AgAYIVE/3/edit – m59 Dec 23 '13 at 22:15
  • If i just want to retrieve a single value from another controller, do i create service for this ? – Chancho Dec 23 '13 at 22:17
  • 2
    @Chancho Yes. Keep in mind the big picture - a controller isn't meant to care about what is done with data. The controller is just a hub for data to/from the view. With that in mind - the controller's job here is just to associate data from the view with data in the service. Then something else that depends on that service can do something with it. If you get the concept, you should see that there's an issue with whatever is using that data depending on a controller. – m59 Dec 23 '13 at 22:27
  • best way for your example is to use a service because they are singleton (just an instance) so when you will update $scope.shared.someData (doesnt matter by which controller) the others also will see the update. that is because they have a reference of the same instance object. – Giovanni Far Mar 27 '16 at 18:10
0

You can use $rootScope, each Angular application has exactly one root scope.

Reference

app.controller('MainController', function ($scope, $rootScope) {
    $rootScope.data = 'App scope data';
}
Steely Wing
  • 16,239
  • 8
  • 58
  • 54
  • 3
    Each module has it's own $rootScope. – Dan Ochiana Oct 15 '14 at 11:58
  • 2
    Even if you could access a global like this, and share state -- this is known as "Common Coupling" and its a 'No-No' level 4 out of 5 (Content Coupling being the highest). #badPractice, #tightCoupling, #theBadTypeOfComplexity . – Cody Dec 13 '14 at 02:49
  • 2
    Mmmm... I'm running Angular 1.5.5 and each module certainly does NOT get it's own $rootScope. – Wrecks Apr 30 '16 at 00:06
  • There is most definitely one $rootScope, or there certainly *should* be, unless you're doing something wrong like passing it between modules or assigning it to another variable somewhere. I'm not seeing anything in the OP's question that indicates that the variable may not be a *static* variable (which would be completely appropriate for the $rootScope, and avoids the complexity of a service). – Chris Halcrow Apr 06 '17 at 23:45