AngularJSのControllerをネストしたときのスコープ

<div ng-controller="ParentCtrl">
  <div ng-show="isShow">foo</div>

  <div ng-controller="ChildCtrl">
    <button ng-click="toggle()">click</button>
  </div>
</div>

こういうHTMLがあったときに、ChildCtrlから$scope.isShowを操作しても反映されない。

これだとダメ。

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

app.controller('ParentCtrl', function($scope) {
  $scope.isShow = false;
});

app.controller('ChildCtrl', function($scope) {
  $scope.toggle = function() {
    $scope.isShow = !$scope.isShow;
  };
});

$scope.$parent.isShowの値を更新ればいける。

app.controller('ParentCtrl', function($scope) {
  $scope.isShow = false;
});

app.controller('ChildCtrl', function($scope) {
  $scope.toggle = function() {
    $scope.$parent.isShow = !$scope.isShow;
  };
});

どうやら

$scope.__proto__ === $scope.$parent

となっているようで、文字通り親のコントローラーを継承しているようになってるみたい。

なのでChildCtrlで$scope.isShowの値を参照しようとすると親のコントローラーの値を参照できるんだけど、代入すると自分自身のプロパティとして新しくつくるんで親には影響しない、ということかな。

なので、以下のように更新する値をオブジェクトにするといける。

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

app.controller('ParentCtrl', function($scope) {
  $scope.data = { isShow: false };
});

app.controller('ChildCtrl', function($scope) {
  $scope.toggle = function() {
    $scope.data.isShow = !$scope.data.isShow;
  };
});

これは$scope.dataを新しくつくるのでなく$scope.__proto__.dataを更新するからだね。