【问题标题】:How to access parent's controller function from within a custom directive using *parent's* ControllerAs?如何使用 *parent's* ControllerAs 从自定义指令中访问父级的控制器功能?
【发布时间】:2015-11-07 03:23:06
【问题描述】:

我需要构建一个将自定义指令转换为 html 的转换指令。

  • 输入如:<link text="hello world"></link>
  • 应该输出到:<a class="someclass" ng-click="linkClicked('hello world')"></a>

linkClicked 应该在指令的父控制器上调用。

如果我是负责持有“链接”指令(使用隔离范围)的 html 的人,那将非常容易,但我不是。这是一个原样输入,我必须想办法仍然这样做。

关于如何使用指令的默认范围进行类似绑定的示例不计其数,但我正在使用带有 controllerAs 的 John Papa's 建议编写我的控制器,但不想在控制器上创建另一个实例指令。

这是我到目前为止所达到的:

(function () {
    'use strict';

    angular
        .module('app')
        .directive('link', link);

    link.$inject = ['$compile'];

    function link($compile) {
        return {
            restrict: 'E',
            replace: true,
            template: '<a class="someclass"></a>',
            terminal: true,
            priority: 1000,
            link: function (scope, element, attributes) {
                element.removeAttr('link'); // Remove the attribute to avoid indefinite loop.

                element.attr('ng-click', 'linkClicked(\'' + attributes.text + '\')');

                $compile(element)(scope);
        },
    };
}
})();
  • $scope.linkClicked = function(text){...} 在父控制器中工作
  • 指令中的element.attr('ng-click', 'abc.linkClicked(..)')(其中父级的 controllerAs 是 abc)-也可以使用

问题是我不知道哪个控制器会使用我的指令并且不能硬编码其中的“abc”名称。

你建议我应该怎么做?

【问题讨论】:

  • 将你需要的东西作为属性传递给指令作用域,......那么父母是什么并不重要
  • 你不应该在你的指令中对控制器做出假设——真的。而且,您不应该假设在使用该指令的视图范围内存在linkClicked()
  • 显然,这个问题没有成功..感谢你们的评论。
  • @wilenx.,我仍然不清楚你想要完成什么。只需遵循隔离范围的正常指令方法并将所需的参数传递给指令即可。还有,&lt;a&gt;的内容应该是什么?
  • @NewDev,(1) 我收到一个 html 字符串,其中包括此链接指令等。它只有那个文本属性。如果可以的话,我会以一种可以以正常方式调用所需函数的方式(如您所建议的那样)重写该链接指令,但我必须自己生成和呈现这些调用。话虽如此,我需要调用我选择的父函数,传入文本进行处理。这是一个糟糕的情况,我明白了,但我仍然需要修补这个东西......(2)的内容与手头的事情无关。

标签: angularjs angularjs-directive angularjs-scope


【解决方案1】:

很难从您的问题中理解您面临的所有限制,但如果您获得的唯一 HTML 是:

<link text="some text">

并且您需要生成对 some 函数的调用,那么该函数必须是:

  1. 由指令假设,或
  2. 传达到指令

#1 是有问题的,因为指令的用户现在需要了解它的内部结构。尽管如此,如果您假设函数名称是 linkClicked(或您想调用的任何名称),并且您的指令的用户必须特别注意为他真正需要的函数起别名(可以用“ controllerAs”):

<div ng-controller="FooCtrl as foo" ng-init="linkClicked = foo.actualFunctionOfFoo">
   ...

   <link text="some text">

   ...
</div>
app.directive("link", function($compile){
  return {
    transclude: "element", // remove the entire element
    link: function(scope, element, attrs, ctrl){
      var template = '<a class="someclass" ng-click="linkClicked(\'' + 
                      attrs.text +
                     '\')">link</a>';

      $compile(template)(scope, function(clone){
        element.after(clone);
      });
    }
  };
});

Demo

#2 通常是通过属性实现的,这在您的情况下是不可能的。但是你也可以创建一种“代理”指令——我们称之为onLinkClick——它可以执行你需要的任何表达式:

<div ng-controller="FooCtrl as foo"
     on-link-click="foo.actualFunctionOfFoo($data)">
   ...

   <link text="some text">

   ...
</div>

link 指令现在需要require: "onLinkClick"

app.directive("link", function($compile){
  return {
    transclude: "element", // remove the entire element
    scope: true,
    require: "?^onLinkClick",
    link: function(scope, element, attrs, ctrl){
      if (!ctrl) return;
      var template = '<a class="someclass" ng-click="localClick()">link</a>';

      scope.localClick = function(){
        ctrl.externalFn(attrs.text);
      };

      $compile(template)(scope, function(clone){
        element.after(clone);
      });
    }
  };
});

app.directive("onLinkClick", function($parse){
  return {
    restrict: "A",
    controller: function($scope, $attrs){
      var ctrl = this;
      var expr = $parse($attrs.onLinkClick);

      ctrl.externalFn = function(data){
        expr($scope, {$data: data});
      };
    },
  };
});

Demo

请注意,有一个link 指令也会在&lt;head&gt; 内的&lt;link&gt; 上执行。因此,请尝试检测它并跳过所有内容。出于演示目的,我使用了一个名为 blink 的指令来避免这个问题。

【讨论】:

  • 谢谢,对我帮助很大!
猜你喜欢
  • 2015-07-08
  • 1970-01-01
  • 2016-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-20
  • 2015-06-28
相关资源
最近更新 更多