角度指令可以将参数传递给指令属性中指定的表达式中的函数吗?

Posted

技术标签:

【中文标题】角度指令可以将参数传递给指令属性中指定的表达式中的函数吗?【英文标题】:Can an angular directive pass arguments to functions in expressions specified in the directive's attributes? 【发布时间】:2013-11-22 06:24:04 【问题描述】:

我有一个表单指令,它使用具有隔离范围的指定 callback 属性:

scope:  callback: '&' 

它位于ng-repeat 内,因此我传入的表达式包含对象的id 作为回调函数的参数:

<directive ng-repeat = "item in stuff" callback = "callback(item.id)"/>

当我完成指令后,它会从其控制器函数调用$scope.callback()。在大多数情况下,这很好,这就是我想做的所有事情,但有时我想从 directive 本身添加另一个参数。

是否存在允许这样的角度表达式:$scope.callback(arg2),导致callbackarguments = [item.id, arg2] 调用?

如果没有,最简洁的方法是什么?

我发现这是可行的:

<directive 
  ng-repeat = "item in stuff" 
  callback = "callback" 
  callback-arg="item.id"/>

scope  callback: '=', callbackArg: '=' 

和调用的指令

$scope.callback.apply(null, [$scope.callbackArg].concat([arg2, arg3]) );

但我不认为它特别整洁,它涉及在隔离范围内放置额外的东西。

有没有更好的办法?

Plunker playground here(打开控制台)。

【问题讨论】:

属性命名为“callback ="误导。它实际上是一个回调评估,而不是回调本身。 @DmitriZaitsev 这是一个回调角度表达式,将评估为 javascript 函数。我认为很明显它本身不是一个 JavaScript 函数。这只是偏好,但我宁愿不必用“-expression”作为我所有属性的后缀。这与ng API 一致,例如ng-click="someFunction()" 是一个计算结果为执行函数的表达式。 我从未见过名为“回调”的 Angular 表达式。它始终是您传递以被调用的函数,名称由此而来。你甚至在你的例子中使用了一个叫做“回调”的函数,让事情变得更加混乱。 我不确定你是困惑还是我。在我的示例中,$scope.callback 由指令定义对象的callback="someFunction" 属性和scope: callback: '=' 属性设置。 $scope.callback 以后调用的函数。实际的属性 value 显然是一个字符串 - html 总是如此。 您将属性和函数命名为相同 - “回调”。这就是混乱的秘诀。真的很容易避免。 【参考方案1】:

如果你像@lex82 提到的那样声明你的回调

callback = "callback(item.id, arg2)"

您可以使用对象映射在指令范围内调用回调方法,它会正确执行绑定。喜欢

scope.callback(arg2:"some value");

不需要$parse。查看我的小提琴(控制台日志)http://jsfiddle.net/k7czc/2/

更新:documentation 中有一个小例子:

& 或 &attr - 提供一种在上下文中执行表达式的方法 父范围。如果未指定属性名称,则属性名称 假定与本地名称相同。范围的给定和小部件定义: localFn:'&myAttr' ,则隔离范围属性 localFn 将指向 count = count + value 表达式的函数包装器。经常 最好通过表达式从隔离范围传递数据 对于父范围,这可以通过传递本地地图来完成 变量名称和值放入表达式包装器 fn。 例如, 如果表达式是增量(数量),那么我们可以指定数量 通过将 localFn 调用为 localFn(amount: 22) 来获取值。

【讨论】:

非常好!这在任何地方都有记录吗? 我认为这不是一个好的解决方案,因为在指令定义中,有时您不知道要传入的参数是什么。 这是一个很好的解决方案,谢谢你,但我相信答案需要稍微调整一下。 lex82 是谁?他提到了什么? 有趣的方法。尽管当您希望允许传递具有 ANY 参数(或多个参数)的任何函数时会发生什么?您对函数及其参数一无所知,并且需要在指令内的某个事件上执行它。怎么办?例如在一个指令上你可以有 onchangefunc='myCtrlFunc(dynamicVariableHere)'【参考方案2】:

其他答案没有错,但是我在指令属性中传递函数时使用了以下技术。

在你的 html 中包含指令时去掉括号:

<my-directive callback="someFunction" />

然后在指令的链接或控制器中“解包”该函数。这是一个例子:

app.directive("myDirective", function() 

    return 
        restrict: "E",
        scope: 
            callback: "&"                              
        ,
        template: "<div ng-click='callback(data)'></div>", // call function this way...
        link: function(scope, element, attrs) 
            // unwrap the function
            scope.callback = scope.callback(); 

            scope.data = "data from somewhere";

            element.bind("click",function() 
                scope.$apply(function() 
                    callback(data);                        // ...or this way
                );
            );
        
    
]);    

“展开”步骤允许使用更自然的语法调用函数。它还确保该指令即使嵌套在可能传递该函数的其他指令中也能正常工作。如果你没有解包,那么如果你有这样的场景:

<outer-directive callback="someFunction" >
    <middle-directive callback="callback" >
        <inner-directive callback="callback" />
    </middle-directive>
</outer-directive>

然后你会在你的内部指令中得到这样的结果:

callback()()()(data); 

在其他嵌套场景中会失败。

我从 http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-3-isolate-scope-and-function-parametershttp://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-3-isolate-scope-and-function-parametersDan Wahlin 的一篇优秀文章中改编了这项技术

我添加了展开步骤,以使调用函数更自然,并解决我在项目中遇到的嵌套问题。

【讨论】:

一个不错的方法,但我无法在回调方法中使用 this 指针,因为它使用了指令的范围。我正在使用 Typescript,我的回调如下所示:public validateFirstName(firstName: string, fieldName: string): ng.IPromise&lt;boolean&gt; var deferred = this.mQService.defer&lt;boolean&gt;(); ... .then(() =&gt; deferred.resolve(true)) .catch((msg) =&gt; deferred.reject(false); ); return deferred.promise; 注意:如果您有嵌套指令并且想要向上传播回调,您需要在每个指令中展开,而不仅仅是一个触发回调。【参考方案3】:

在指令中(myDirective):

...
directive.scope =   
    boundFunction: '&',
    model: '=',
;
...
return directive;

在指令模板中:

<div 
data-ng-repeat="item in model"  
data-ng-click='boundFunction(param: item)'>
item.myValue
</div>

来源:

<my-directive 
model='myData' 
bound-function='myFunction(param)'>
</my-directive>

...myFunction 在控制器中定义。

请注意,指令模板中的param 整齐地绑定到源代码中的param,并设置为item


要从指令的link 属性(“内部”)调用,请使用非常相似的方法:

...
directive.link = function(isolatedScope) 
    isolatedScope.boundFunction(param: "foo");
;
...
return directive;

【讨论】:

当有 In source: bound-function='myFunction(obj1.param, obj2.param)'> 那么如何进行呢?【参考方案4】:

是的,有一个更好的方法:您可以在指令中使用 $parse service 在父作用域的上下文中评估表达式,同时将表达式中的某些标识符绑定到仅在指令内可见的值:

$parse(attributes.callback)(scope.$parent,  arg2: yourSecondArgument );

将此行添加到指令的链接函数中,您可以访问指令的属性。

然后您的回调属性可能会设置为callback = "callback(item.id, arg2)",因为 arg2 通过指令内的 $parse 服务绑定到 yourSecondArgument。像 ng-click 这样的指令让您可以通过传递给指令的表达式中的 $event 标识符访问点击事件,而正是使用这种机制。

请注意,您不必使用此解决方案将callback 设为您的隔离范围的成员。

【讨论】:

使用 scope.$parent 会使指令“泄漏”——它“了解”太多外部世界,而精心设计的封装组件不应该这样做。 嗯,它知道它有一个父作用域,但它不访问作用域中的特定字段,所以我认为这是可以容忍的。【参考方案5】:

对我来说,以下工作:

in 指令声明如下:

.directive('myDirective', function() 
    return 
        restrict: 'E',
        replace: true,
        scope: 
            myFunction: '=',
        ,
        templateUrl: 'myDirective.html'
    ;
)  

在指令模板中使用如下方式:

<select ng-change="myFunction(selectedAmount)">

然后当你使用指令时,像这样传递函数:

<data-my-directive
    data-my-function="setSelectedAmount">
</data-my-directive>

你通过它的声明传递函数,它被指令调用并填充参数。

【讨论】:

以上是关于角度指令可以将参数传递给指令属性中指定的表达式中的函数吗?的主要内容,如果未能解决你的问题,请参考以下文章

将参数传递给角度指令

将文件x中指定的函数作为命令行参数传递给python中的文件y的最佳方法

AngularJS:如何将参数/函数传递给指令?

Angularjs - 将参数传递给指令

如何将参数传递给 ssis 中的 ado.net 源?

Dockerfile 指令