如何从具有隔离范围的指令中公开行为?

Kon*_*rus 34 javascript angularjs angularjs-directive

如何从指令公开方法?我知道我应该使用数据属性,但我真的想暴露行为,而不是数据.父控制器可以调用的东西.

假设我的DOM看起来像:

<div ng-app="main">
    <div ng-controller="MyCtrl">
        <button ng-click="call()" >Call</button>
        <div id="container" my-directive> </div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

JavaScript的:

angular.module("main", []).controller("MyCtrl", function($scope) {
    $scope.call = function() {
        $scope.myfn();
    };
}).directive("myDirective", function() {
    return {
        // scope: {},
        controller: function($scope) {
            $scope.myfn = function() {
                console.log("myfn called");
            }
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

jsFiddle:http://jsfiddle.net/5gDjQ/7/

如果scope被注释掉(即指令没有隔离范围),它就可以正常工作.当我按下按钮时,myfn会调用并登录到控制台.

一旦我取消注释scope,它就不起作用.myfn是在子范围上定义的,父母不容易获得.

在我的情况下,我认为污染父范围是一个坏主意,我真的想避免它.

那么,我如何将一个函数从指令暴露给父控制器?或者:如何从父控制器调用指令上的方法?

Roy*_*ove 26

您可以通过在与控制器双向绑定的范围中设置变量(使用"=")来使用隔离范围执行此操作.在您的指令中,您可以将函数分配给该变量,而angular将使用绑定在控制器中查找相应的变量.该变量将指向控制器可以调用的函数.

http://jsfiddle.net/GWCCr/

html:注意新的attrib:

<div ng-app="main">
    <div ng-controller="MyCtrl">
        <button ng-click="call()" >Call</button>
        <div id="container" my-directive my-fn="fnInCtrl"> </div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

JS:

angular.module("main", []).controller("MyCtrl", function($scope) {
    $scope.call = function() {
        $scope.fnInCtrl();
    };
}).directive("myDirective", function() {
    return {
        scope: {
            myFn: '='
        },
        controller: function($scope) {
            $scope.myFn = function() {
                console.log("myfn called");
            }
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

  • 这是Angular最好的吗?我的意思是,如果顶部控制器和底部指令之间有多个指令,那么必须通过所有中间指令明确地传递该函数.并且在顶级控制器上公开函数(需要访问顶级$ scope数据)似乎是一个非常基本的想法作为Angular新手. (6认同)

Dzi*_*inX 16

我认为你应该问自己:为什么我要调用指令中定义的函数,而不是试图弄清楚如何调用隐藏在指令中的函数?

我能想到的一个原因是:触发指令的某些行为,这些行为也可以由指令内的应用程序用户触发.

如果是这样,那么显而易见的Angulary 事件就是在包含应该对其做出反应的指令的范围上广播一个事件.然后该指令将监听该事件并自行触发其功能.

这还有其他好处:

  • 如果需要,可以在事件数据对象中发送参数
  • 你可以在多个指令中触发反应(例如,如果它们形成一个集合)
  • 您可以与范围层次结构深处的指令进行通信(例如,如果指令位于其他指令内的另一个指令中,等等),而不通过每个嵌套指令传递函数回调
  • 它不会破坏指令的隔离

让我们试着想出一个非常简单的例子:假设我们有一个小部件,显示从某个地方下载的随机鼓舞人心的报价.它还有一个按钮,可以将报价更改为其他报价.

这是指令的模板:

<p>{{ quote }}</p>
<button ng-click="refreshQuote()"></button>
Run Code Online (Sandbox Code Playgroud)

这是指令的代码:

app.directive("randomQuote", function () {
  return {
    restrict: "E",
    scope: {},
    link: function (scope) {
      scope.refreshQuote = function () {
        scope.quote = ... // some complicated code here
      };
      scope.refreshQuote();
    }
  };
});
Run Code Online (Sandbox Code Playgroud)

请注意,该指令完全是自包含的:它具有隔离范围并自行进行引用.

让我们假设我们也希望能够刷新控制器的报价.这可以像在控制器代码中调用它一样简单:

$scope.$broadcast("refresh-random-quote");
Run Code Online (Sandbox Code Playgroud)

要添加事件处理程序,我们必须将此代码添加到link指令的函数中:

scope.$on("refresh-random-quote", function () {
  scope.refreshQuote();
});
Run Code Online (Sandbox Code Playgroud)

这样,我们创建了一个从控制器到指令的单向通信通道,它不会破坏指令的隔离,如果指令嵌套在广播事件的代码的作用域层次结构中,也可以工作. .


Mar*_*cok 7

如何将指令中的函数公开给父控制器?
或者:如何从父控制器调用指令上的方法?

好吧,我认为你不应该尝试这样做(即,将控制器行为耦合到指令),但如果你必须......这是你可以做到的一种方法:将控制器函数传递给你的指令,指令可以调用通知控制器的指令功能:

<div id="container" my-directive cb="setDirectiveFn(fn)"></div>

directive("myDirective", function() {
    return {
       scope: { cb: '&' },
        controller: function($scope) {
            $scope.myfn = function() {
                console.log("myfn called");
            }
            $scope.cb({fn: $scope.myfn});
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

小提琴