Javascript 自定义子指令访问父级的范围

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31200906/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 06:22:19  来源:igfitidea点击:

Custom child directive accessing scope of parent

javascriptangularjsangularjs-directiveangularjs-scope

提问by Sriramajeyam Sugumaran

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.

我的 angularJS 应用程序中有两个自定义指令。一个充当父母,另一个充当孩子。我正在尝试访问 child 指令中的 parent 范围。但我没有得到所需的输出。

<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

https://jsbin.com/nozuri/edit?html,js,output 中提供了相应的 JSFiddle

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?

谁能告诉我我在这里做错了什么?

采纳答案by kwangsa

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

城市指令 $parent 是国家指令的嵌入范围。

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

state 指令的嵌入范围是为 state 指令的 $parent 继承的,它是控制器,因此这就是 $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 )

嵌入作用域的 $parent 是状态指令隔离作用域( scope = {} ),这就是为什么 $parent.$parent.MyName = Tamilnadu (Angular 1.3 更新的一部分)

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?

发生的事情的一些细节: 如何从 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.

transclude: true - 该指令创建一个新的“transcluded”子作用域,该子作用域原型继承自父作用域。如果该指令还创建了一个隔离作用域,则嵌入的和隔离的作用域是同级的。每个作用域的 $parent 属性引用相同的父作用域。

Angular v1.3 更新:如果指令还创建了一个隔离范围,则被嵌入的范围现在是隔离范围的子级。嵌入的和隔离的作用域不再是兄弟作用域。嵌入作用域的 $parent 属性现在引用隔离作用域。

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

马修的回答对于亲子指令通信也是正确的。

回答by Matthew King

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();
      }
  }});

回答by gr3g

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 遇到 transclude 时,它​​会在将 HTML 替换为模板或 templateUrl 内容之前克隆 HTML。然后,当它遇到 ng-transclude 时,它​​会编译被嵌入的内容,但将其链接到父作用域而不是指令的独立作用域。因此,嵌入的内容仍然可以访问父控制器及其内容,而指令 HTML 具有隔离的范围(或新的范围,视情况而定)。

AngularJS Up and Running

AngularJS 启动并运行

回答by Pawe? Smo?ka

Check out sollution of my directive, it works with a lot of parrents. What I done was to remove transclude and require params. Do not bother about dirty html, just watch js, simple as f.. :D

查看我的指令的解决方案,它适用于很多父母。我所做的是删除 transclude 和 require params。不要理会脏的 html,只看 js,就像 f.. 一样简单:D

    CRM.directive('inputwv', function ($compile) {
    var getTemplate = function(contentType) {
        var template = '';

        switch(contentType) {
                case '3':
                    template = '<input type="number" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px;width:100px">'
                    break;
                case '0':
                    template = '<input type="text" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px">'
                    break;
                case '1':
                    template = '<input type="text" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px">'
                    break;
                case '2':
                    template = '<textarea class="materialize-textarea teal-text" type="text" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px">'
                    break;
                case '4':
                    template = '<input type="text" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px">'
                    break;
                case '5':
                    template = '<input type="date" class="datepicker" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px"><script type="text/javascript">$(\'.datepicker\').pickadate({selectMonths: true, selectYears: 15});</script>'
                    break;
                default:
                    template = '<textarea class="materialize-textarea teal-text" type="text" ng-init="inputHide[$parent.$index][$index]=false" ng-blur="inputHide[$parent.$index][$index]=false" ng-Enterd="updateRecord(row[0], $parent.$index)" ng-Enteru="inputHide[$parent.$index][$index]=false" ng-model="row[$index]" ng-change="row[$index]" ng-value="row[$index]" ng-Right-Click="click(element, $index, $parent.$index )" ng-esc="inputHide[$parent.$index][$index]=false" style="cursor:cell;border-bottom:0px">'
            }

        return template;
}

    var linker = function(scope, element, attrs) {
        element.html(getTemplate(attrs.typ)).show();

        $compile(element.contents())(scope);
    }

    return {
        restrict: "E",
        link: linker
    };
});