繁体   English   中英

将父控制器方法传递给包含子指令的对象

[英]Passing parent controller method to transcluding child directive

我正在尝试从包含子指令的链接功能访问父指令的控制器方法,但运气不好。 当我将孩子作为父母模板的一部分或从父母ng-controller传递给孩子时,它会起作用。 不应在角度1.4中也包括创建子范围吗?

使用Javascript:

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

app.controller('AppController', function($scope) {
  $scope.ctrlFn = function() {
    alert('hello');
  };
});

app.directive('outerDirective', function() {
  return {
    restrict: 'A',
    scope: {
      ctrlFn : '&'
    },
    controller: 'AppController',
    transclude:true,
    template: '<div ng-transclude></div>',
    link: function(scope, element, attributes) {
      scope.outerFunction = function() {

        scope.ctrlFn();
      };
    }
  };
});

app.directive('innerDirective', function() {
  return {
    scope: {
      ctrlFn : '&'
    },
    replace:true,
    template: '<button ng-click="innerFunction()">Child Directive</button>',
    link: function(scope, element, attributes) {
      scope.innerFunction = function() {

        scope.ctrlFn();
      };
    }
  };
});

HTML:

<div id="app" ng-app="app">
  <div outer-directive ctrl-fn="ctrlFn">

    <div inner-directive ctrl-fn="ctrlFn()"></div>

  </div>
</div>

JSBin

问题

因为您将scope: { ctrlFn: '&', }放在outerDirective ,所以它创建了一个隔离范围

“隔离”作用域与常规作用域的不同之处在于,它不原型地继承自其父作用域。 这在创建可重用的组件时非常有用,该组件不应意外读取或修改父范围中的数据。 请注意,没有templatetemplateUrl的隔离范围指令不会将隔离范围应用于其子元素。

隔离作用域的一个用例是能够scope.$watch链接函数中作用域上的scope.$watch表达式,即使指令没有模板也很有用。 隔离范围的另一种用途是在指令模板中为指令和插值提供数据(如果有的话)。

但是,这个范围被被包容的孩子忽略了。 包含时,您会得到一个特殊的包含范围 ,它会特别忽略此隔离范围:

此范围是特殊的,因为它是指令范围的子级(因此,在销毁指令范围时会被销毁),但是它继承了从中获取该范围的属性。

这意味着传递给link函数的scope仅对模板可见。 所包含的任何内容都将看到您指令的父范围,而忽略隔离范围。

指令彼此通信的一种方法是require require指令可以将容器指令的控制器注入到任何子级的link函数中。 另外, require通过DOM树而不是范围继承树来搜索祖先。 因此,当您需要控制器时,被包含的内容可以获取包含该内容的指令的控制器。 例如,您的代码可以通过以下方式适应使用控制器:

JavaScript的:

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

app.controller('AppController', function($scope) {
  $scope.ctrlFn = function() {
    alert('hello');
  };
});

app.directive('outerDirective', function() {
  return {
    restrict: 'A',
    scope: {
      ctrlFn : '='
    },
    controller: function OuterDirectiveController($scope) {
      this.outerFunction = function () {
        return $scope.ctrlFn();
      };
    },
    transclude:true,
    template: '<div ng-transclude></div>'
  };
});

app.directive('innerDirective', function() {
  return {
    replace:true,
    template: '<button ng-click="innerFunction()">Child Directive</button>',
    link: function(scope, element, attributes, outerDirective) {
      scope.innerFunction = function() {
        outerDirective.outerFunction();
      };
    },
    scope: {},
    require: '^outerDirective'
  };
});

注意,我还将ctrlFn: '&'更改为ctrlFn: '='因为当您想在调用程序中执行表达式时, '&'才是ctrlFn: '='的。 例如,当您执行类似<my-directive on-something-happened="x = $event.value"/> 但是,您试图将函数作为值传递,而不是试图传递可执行的角度表达式。

注意,我在innerDirective上设置了scope: {} ,但我将其保留为空。 这向AngularJS指示了我想要一个隔离范围-我不想覆盖父范围中的任何值。 然后在链接函数中,填充scope.innerFunction以便我的模板可以访问引用所需控制器的innerFunction 我也可以将控制器也直接存储在示波器上,并为innerDirective保存几个LOC:

{
  template: '<button ng-click="outerDirective.outerFunction()">Child Directive</button',
  link: function (scope, element, attributes, outerDirective) {
    scope.outerDirective = outerDirective;
  },
  // (other keys omitted for brevity).
}

HTML:

<div id="app" ng-app="app" ng-controller="AppController">
  <div outer-directive ctrl-fn="ctrlFn">
    <div inner-directive></div>
  </div>
</div>

另请注意,我更换了您的控制器。 现在,您的AppController使用ng-controller="AppController"连接到根应用程序元素。 这使您可以从应用程序控制器设置范围。 然后,每个伪指令都基于传递给它们的数据独立运行,而不是用作根范围。 我认为,指令的通常用例是可重用模板或做任何需要直接与DOM交互的事情,而不是一次用于间接连接根应用程序控制器。

更新的JSBin

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM