【问题标题】:Update controller scope from directive从指令更新控制器范围
【发布时间】:2015-04-30 10:52:28
【问题描述】:

我正在使用 AngularJS 指令创建可重用的 UI 组件。我想要一个控制器,其中包含我的业务逻辑和嵌套组件(指令)。我希望指令能够操纵控制器范围内的单个属性。这些指令需要有一个隔离作用域,因为我可能会多次使用同一个指令,并且每个实例都需要绑定到特定的控制器作用域属性。

到目前为止,我可以将更改应用回控制器范围的唯一方法是从指令中调用 scope.$apply()。但是当我因为 rootScope:inprog(范围操作正在进行)错误而在 ng-click 回调中时,这会中断。

所以我的问题:当子指令更新了控制器范围内的值时,让我的控制器知道的最佳方法是什么?

我考虑过在控制器上设置一个指令可以调用以进行更新的函数,但这对我来说似乎很重。

这是我在 ng-click 回调中中断的代码。 请记住,我不只是想解决 ng-click 问题。 我想要应用可重用指令来修改父作用域/模型的最佳整体解决方案。

html

<div ng-controller="myCtrl">
    <my-directive value="val1"></my-directive>
</div>

控制器

...
.controller('myCtrl', ['$scope', function ($scope) {
    $scope.val1 = 'something';
}});

指令

...
.directive('myDirective', [function () {

return {
    link: function(scope) {
        scope.buttonClick = function () {
            var val = 'new value';
            scope.value = val;
            scope.$apply(); 
        };
    },
    scope: {
        value: '='
    },
    template: '<button ng-click="buttonClick()"></button>'
};
}]);

【问题讨论】:

  • 你可以在 $rootScope 上发出事件。
  • @camden_kid 我希望有更好的封装。至少我会使用我考虑过的控制器方法。不过,我不认为我想在根范围上添加更多聊天内容。
  • 您不需要调用 $apply(),因为 buttonClick 函数由 ng-click 指令调用,因此不会在 angular 事件处理之外执行。如果你想修改一个属性,那么你所拥有的就可以了(除非你不应该使用 $apply())。如果要调用回调函数,则使用'&amp;' 而不是'=' 传递可调用函数。
  • 你可以注入一个服务。我注意到的一件事是指令元素标记中有一个按钮。它不会那样工作。您的指令中需要一个模板(或 templateURL)。
  • @camden_kid 你是对的模板。为简洁起见,我以这种方式发布,但我会进行编辑。

标签: angularjs angularjs-directive angularjs-scope


【解决方案1】:

指令中双向数据绑定的目的正是您要问的——“[允许]指令修改父范围/模型。”

首先,请仔细检查您是否已在指令属性上正确设置了双向数据绑定,该指令属性公开了您要在作用域之间共享的变量。在控制器中,您可以使用$watch 来检测更新,如果您需要在值更改时执行某些操作。此外,您可以选择向指令添加事件处理程序属性。这允许指令在发生某些事情时调用函数。这是一个例子:

<div ng-controller="myCtrl">
    <my-directive value="val1" on-val-change="myFunc"> <!-- Added on-change binding -->
        <button ng-click="buttonClick()"></button>
    </my-directive>
</div>

【讨论】:

  • 您为我指明了正确的道路。我的问题与双向绑定和原语纠缠不清。
【解决方案2】:

我认为您关于$scope.apply 的问题是转移话题。我不确定它在你改进这个演示和问题时为你解决了什么问题,但这不是它的目的,FWIW your example works for me without it

您不应该担心这个问题(“让控制器知道...... [某物] 修改了范围上的值”); Angular 的数据绑定会自动处理这个问题。

这里有点复杂,因为使用指令,需要担心多个范围。外部作用域属于&lt;div ng-controller=myCtrl&gt;,该作用域有一个.val 属性,还有一个由&lt;my-directive&gt; 创建的内部作用域,它也有一个.val 属性,myDirective 内部的buttonClick 处理程序修改了内在的。但是您使用 value: '=' 声明了 myDirective 的范围,它设置了该属性值在内部和外部范围之间的双向同步。

所以它应该自动工作,并且在我根据您的问题代码创建的 plunker 中,它确实会自动工作。

那么scope.$apply 是从哪里来的呢?它明确地用于在 Angular 不知道它需要时触发摘要循环。 (如果你在 Angular 确实知道它已经需要一个摘要循环时使用它,你会得到一个嵌套的摘要循环和你注意到的“inprog”错误。)Here's the doc link,我从中引用“$apply() 用于执行来自角度框架外部的角度表达式”。例如,当响应使用非 Angular 方法(直接 DOM 事件绑定、jQuery、socket.io 等)设置的事件处理程序时,您需要使用它。如果您在 Angular 应用程序中使用这些机制,通常最好将它们包装在处理 Angular 到非 Angular 接口的指令或服务中,这样您的应用程序的其余部分就不必担心了。

(scope.$apply 实际上是scope.$digest 的包装器,它还管理异常处理。这在文档中不是很清楚。我发现更容易理解$digest 的名称/行为,然后考虑@ 987654333@ 是“我应该使用的更友好的$digest 版本”。)

关于$apply的最后一点;它需要一个函数回调参数,你应该在这个回调中完成工作。如果你做了一些工作,然后在没有参数的情况下调用$apply,它可以工作,但此时它与$digest 相同。所以如果你确实需要在这里使用$apply,它应该看起来更像:

scope.buttonClick = function() { scope.$apply(function() { scope.value = newValue; }); });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多