Question

Parent controller set to 'parentCtrl as vm' and chield set to 'childCtrl as vmc' to be no name conflict and it works well.

How can I get access to parent controller in child controller?

Note that '$scope.$parent' did not work.

Was it helpful?

Solution

To access the parent controller using the '$scope' notation just use '$scope.$parent'.

However the 'controller as vm' notation lacked a detail that makes it work with some behavior:

'$scope.$parent.vm'

app.controller('childCtrl', [
    '$scope', function ($scope) {
        var vmc = this;

        // To protected access as vmc.parent
        Object.defineProperty(vmc, 'parent', {
            get: function () {
                return $scope.$parent.vm;
            }
        });
    }
]);

However changing the parent objects have side effects on primitive objects which may be understood in the following angular.js documentation.

JavaScript Prototypal Inheritance

Example:

Working example on JS Bin

<section class="parent" 
         data-ng-controller="parentCtrl as vm">
  <input data-ng-model="vm.name">

  <!-- have to change the prefix after the 'as' not to have conflict -->
  <section class="child"
           data-ng-controller="childCtrl as vmc">
    <input data-ng-model="vm.name">
    <!-- same results -->
    <input data-ng-model="$parent.vm.name">
    <!-- same results -->
    <input data-ng-model="vmc.parent.name">
    <!-- same results -->
    <button data-ng-click="vmc.changeName()">Change name</button>
  </section>
</section>

(function(){
  var app = angular.module('app', []);
  app.controller('parentCtrl', [
        '$scope', function ($scope) {
            var vm = this;
            vm.name = 'Julia';
        }
    ]);
  app.controller('childCtrl', [
        '$scope', function ($scope) {
            var vmc = this;

            // To protected access as vmc.parent
            Object.defineProperty(vmc, 'parent', {
                get: function () {
                    return $scope.$parent.vm;
                }
            });
          vmc.changeName = function(){
            vmc.parent.name = 'Other ' + vmc.parent.name;
          };
        }
    ]);
})();

OTHER TIPS

Instead what you want to do is set up event handling between controllers. That is the proper way to communicate between controllers.

For instance in your parent controller you might set:

$scope.$on('getParentInfo', function(event, dataFromChild) {
   $scope.$broadcast('provideParentInfo', $scope.parentData);
});

and in your child controller you can request the parent data:

$scope.$emit('getParentInfo', $scope.childData);

$scope.$on('provideParentInfo', function(event, parentData){
    // do something with parent data
});

You need to do some additional research on when to use/not to use $broadcast and $emit and alternative methods that handle automatically unbinding listeners when the scope is destroyed such as $onRootScope.

Additionally, depending on the hierarchy of your controllers, i find it is helpful to $emit or $broadcast data when the controller loads in the case that the get event from the receiving controller is sent before the event listener is the controller with the data.

If you want to share data between parent and child controller, I believe the best way to do it is to create some service which holds shared methods\data. At least you will not see $scope notation (that you are trying to avoid). You'll get smth like this:

angular.module('app').service('SharedModel', function(){
    var model = this;

    var sharedData;

    model.setData = function(data) {
        sharedData = data;
    };
    model.getData = function() {
        return sharedData;
    };
});

angular.module('app').controller('ParentController', function(SharedModel){
    SharedModel.setData("value");
});

angular.module('app').controller('ChildController', function(SharedModel){
    var data = SharedModel.getData();
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top