Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom child directive accessing scope of parent

I am having two custom directives in my angularJS app. One act as a parent and other act as child. I am trying to access parent's scope inside child directive. But I am not getting the desired output.

<div ng-controller="CountryCtrl">
{{myName}}
    <div ng-controller="StateCtrl">
        <state nameofthestate="'Tamilnadu'">
            <city nameofthecity="'Chennai'"></city>
        </state>
    </div>
</div>

and my script looks like

var app = angular.module("sampleApp",[]);
app.controller("CountryCtrl",function($scope){
    $scope.myName = "India";
});
app.controller("StateCtrl",function($scope){
});
app.directive("state",function(){return {
    restrict : 'E',
    transclude: true,
    scope : { myName  : '=nameofthestate'},
    template:"**   {{myName}} is inside {{$parent.myName}}<br/><ng-transclude></ng-transclude>"
}});
app.directive("city",function(){return {
    restrict : 'E',
    require:'^state',
    scope : { myName  : '=nameofthecity'},
    template:"****   {{myName}} is inside {{$parent.myName}} which is in {{$parent.$parent.myName }}<br/> "
}});

Corresponding JSFiddle available in https://jsbin.com/nozuri/edit?html,js,output

The output which i am getting is

India
** Tamilnadu is inside India
**** Chennai is inside India which is in Tamilnadu

and the expected output is

India
** Tamilnadu is inside India
**** Chennai is inside Tamilnadu which is in India

Can anyone educate me what i am doing wrong here?

like image 449
Sriram Avatar asked Jul 03 '15 07:07

Sriram


People also ask

How do I get parent scope in directive?

You can still access the parent scope using $parent , but this is not normally recommended. Instead, you should specify which parent scope properties (and/or function) the directive needs via additional attributes on the same element where the directive is used, using the = , @ , and & notation.

How do you access child controller scope in parent controller?

In a nutshell: You cannot access child scopes from a parent scope. Your solutions: Define properties in parents and access them from children (read the link above) Use a service to share state.

What is scope parent?

Angular scopes include a variable called $parent (i.e. $scope. $parent ) that refer to the parent scope of a controller. If a controller is at the root of the application, the parent would be the root scope ( $rootScope ). Child controllers can therefore modify the parent scope since they access to it.

What is a custom directive?

Custom directives are used in AngularJS to extend the functionality of HTML. Custom directives are defined using "directive" function. A custom directive simply replaces the element for which it is activated.


3 Answers

The city directive $parent is a transcluded scope of state directive.

The transcluded scope of the state directive is inherit for $parent of state directive which is controller thus that is why $parent.MyName = India.

The $parent of transcluded scope is the state directive isolated scope ( scope = {} ) that is why $parent.$parent.MyName = Tamilnadu ( Part of Angular 1.3 update )

enter image description here

Bit of detail of what happen : How to access parent scope from within a custom directive *with own scope* in AngularJS?

transclude: true - the directive creates a new "transcluded" child scope, which prototypically inherits from the parent scope. If the directive also creates an isolate scope, the transcluded and the isolate scopes are siblings. The $parent property of each scope references the same parent scope.

Angular v1.3 update: If the directive also creates an isolate scope, the transcluded scope is now a child of the isolate scope. The transcluded and isolate scopes are no longer siblings. The $parent property of the transcluded scope now references the isolate scope.

Also Matthew's answer is correct for parent-child directive communications.

like image 181
kwangsa Avatar answered Oct 18 '22 01:10

kwangsa


Does this work for you? Adapted from this answer.

There isn't a straightforward way to access the transcluded content's parent element, so we inject the parent controller into the child to access its scope.

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

  app.controller("CountryCtrl",function($scope){
      $scope.myName = "India";
  });

  app.controller("StateCtrl",function($scope){
  });

  app.directive("state",function(){return {
      restrict : 'E',
      transclude: true,
      scope : { myName  : '=nameofthestate'},
      template:"**   {{myName}} is inside {{$parent.myName}}<br/><ng-transclude></ng-transclude>",
      controller: function ($scope) {
        this.getName = function () {
          return $scope.myName;
        }
      }
  }});

  app.directive("city",function(){return {
      restrict : 'E',
      require:'^state',
      scope : { myName  : '=nameofthecity'},
      template:"****   {{myName}} is inside {{parentName}} which is in {{$parent.myName }}<br/> ",
      link: function(scope, element, attrs, ctrl) {
        scope.parentName = ctrl.getName();
      }
  }});
like image 15
Matthew King Avatar answered Oct 18 '22 02:10

Matthew King


When AngularJS encounters transclude , it clones the HTML before replacing it with the template or templateUrl contents. Then, when it encounters ng-transclude , it compiles the transcluded content, but links it to the parent scope instead of the isolated scope of the directive. Thus, the transcluded content still has access to the parent controller and its content, while the directive HTML has an isolated scope (or a new scope, as the case might be).

AngularJS Up and Running

like image 2
gr3g Avatar answered Oct 18 '22 00:10

gr3g