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

时间:2015-07-03 07:20:49

标签: javascript angularjs angularjs-directive angularjs-scope

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

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

我的脚本看起来像

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/> "
}});

https://jsbin.com/nozuri/edit?html,js,output

中提供的相应JSFiddle

我得到的输出是

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

,预期输出为

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

任何人都可以教育我在这里做错了吗?

4 个答案:

答案 0 :(得分:28)

city指令$ parent是一个transcluded状态指令。

state指令的transcluded范围是继承状态指令的$ parent,这是控制器,因此$ parent.MyName = India。

transcluded范围的$ parent是状态指令隔离范围(scope = {}),这就是为什么$ parent。$ parent.MyName = Tamilnadu(Angular 1.3更新的一部分)

enter image description here

发生的事情的一些细节: How to access parent scope from within a custom directive *with own scope* in AngularJS?

  

transclude:true - 该指令创建一个新的“transcluded”子节点   范围,原型继承自父范围。如果   指令还创建了一个隔离范围,transcluded和   隔离范围是兄弟姐妹。每个范围的$ parent属性   引用相同的父范围。

     

Angular v1.3更新:如果该指令还创建了隔离范围,   被抄送的范围现在是孤立范围的子代。该   被抄袭和孤立的范围不再是兄弟姐妹。 $ parent   现在,transcluded范围的属性引用了隔离范围。

Matthew的回答对于父子指令通信也是正确的。

答案 1 :(得分:15)

这对你有用吗?改编自this answer

没有一种简单的方法可以访问被转换内容的父元素,因此我们将父控制器注入子节点以访问其范围。

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

答案 2 :(得分:2)

  

当AngularJS遇到transclude时,它会先克隆HTML   用模板或templateUrl内容替换它。然后,当它   遇到ng-transclude,它会编译被抄送的内容,但是   将它链接到父范围而不是孤立的范围   指示。因此,被抄送的内容仍然可以访问   父控制器及其内容,而指令HTML有一个   隔离范围(或新范围,视情况而定)。

AngularJS启动并运行

答案 3 :(得分:1)

检查我的指令的解决方案,它适用于许多公民。我做的是删除transclude并要求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
    };
});