New Dev New Dev - 3 months ago 14
AngularJS Question

Accessing inherited scope with Controller As approach

With the original way to define controllers, accessing the parent's scope was fairly trivial, since the child scope prototypically inherits from its parent.

app.controller("parentCtrl", function($scope){
$scope.name = "Parent";
})
.controller("childCtrl", function($scope){
$scope.childName = "child of " + $scope.name;
});

<div ng-controller="parentCtrl">
{{name}}
<div ng-controller="childCtrl">
{{childName}}
</div>
</div>


The Controller-As approach seems to be the recommended way to declare a controller. But with Controller-As, the above approach no longer works.

Sure, I can access the parent scope with
pc.name
from the View:

<div ng-controller="parentCtrl as pc">
{{pc.name}}
<div ng-controller="childCtrl as cc">
{{cc.childName}}
</div>
</div>


I do have some issues with this (potential for spaghetti code), but this question is about accessing the parent scope from the child controller.

The only way I can see this working is:

app.controller("parentCtrl", function(){
this.name = "parent";
})
.controller("childCtrl", function($scope){
$scope.pc.name = "child of " + $scope.name;
// or
$scope.$parent.pc.name = "child of " + $scope.name;

// there's no $scope.name
// and no $scope.$parent.name
});


So now, the child controller needs to know about "
pc
" - except, this should (in my mind) be restricted to the view. I don't think a child controller should know about the fact that a view decided to declare a
ng-controller="parentCtrl as pc"
.

Q: What's the right approach then?

EDIT:

Clarification: I'm not looking to inherit a parent controller. I am looking to inherit/change the shared scope. So, if I was to amend the first example, I should be able to do the following:

app.controller("parentCtrl", function($scope){
$scope.someObj = {prop: "not set"};
})
.controller("childCtrl", function($scope){
$scope.someObj.prop = "changed";
});

Answer

After researching, I came to the following realization:

Controller-As approach is NOT a substitute for using $scope. Both have their place, and can/should be used together judiciously.

  1. $scope does exactly what the name implies: i.e. it defines ViewModel properties on the $scope. This works best for sharing scope with nested controllers that can use the $scope to drive their own logic or to change it.
  2. Controler-As defines the entire controller object as a ViewModel with a named scope (via the controller's alias). This works best only in the View (but not other controllers), if the View decides if it wants to reference a specific controller ViewModel.

Here's an example:

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

// Then the controllers could choose whether they want to modify the inherited scope or not:
app.controller("ParentCtrl", function($scope) {
    this.prop1 = {
      v: "prop1 from ParentCtrl"
    };
    $scope.prop1 = {
      v: "defined on the scope by ParentCtrl"
    };
  })
  .controller("Child1Ctrl", function($scope) {})
  .controller("Child2Ctrl", function($scope) {
    // here, I don't know about the "pc" alias
    this.myProp = $scope.prop1.v + ", and changed by Child2Ctrl";
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js"></script>

<body ng-app="myApp">
  <div ng-controller="ParentCtrl as pc">
     <div ng-controller="Child1Ctrl">
        <div>I know about the "pc" alias: {{pc.prop1.v}}</div>
     </div>
     <div ng-controller="Child2Ctrl as ch2">
       <div>I only care about my own ViewModel: {{ch2.myProp}}</div>
    </div>
  </div>