web-dev-qa-db-ja.com

角度ディレクティブは、ディレクティブの属性で指定された式の中で関数に引数を渡すことができますか?

特定の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の遊び場 (コンソールを開いてください)。

156
Ed Hinchliffe

@ Lex82のようにコールバックを宣言した場合

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

オブジェクトマップを使用してディレクティブスコープ内でコールバックメソッドを呼び出すことができ、それによってバインディングが正しく行われます。好き

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

$ parseを必要とせずに。私のフィドルを参照してください(コンソールログ) http://jsfiddle.net/k7czc/2/

更新ドキュメント にこれの小さな例があります。

&or&attr - 親スコープのコンテキストで式を実行する方法を提供します。属性名が指定されていない場合、属性名はローカル名と同じであると見なされます。スコープのウィジェット定義が{localFn: '&myAttr'}であると仮定すると、スコーププロパティlocalFnを分離すると、count = count + value式の関数ラッパーがポイントされます。多くの場合、孤立したスコープから式を介して親スコープにデータを渡すことが望ましいです。これは、ローカル変数名と値のマップを式ラッパーfnに渡すことで実現できます。 たとえば、式がincrement(amount)の場合、localFnをlocalFn({amount:22})として呼び出すことで、amountの値を指定できます。

211
Chandermani

他の答えに問題はありませんが、ディレクティブ属性で関数を渡すときは、次の手法を使用します。

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-parameters

関数の呼び出しをより自然にし、プロジェクトで発生したネストの問題を解決するために、アンラップステップを追加しました。

57
ItsCosmo

指令(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;
39
Ben

はい、もっと良い方法があります。式の中の特定の識別子を自分のディレクティブの中でしか見えない値にバインドしながら、親スコープのコンテキストで式を評価するには、ディレクティブで $ parse service を使用できます:

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

この行をディレクティブのリンク関数に追加して、ディレクティブの属性にアクセスできます。

Arg2はディレクティブ内の$ parseサービスによってyourSecondArgumentにバインドされているため、コールバック属性はcallback = "callback(item.id, arg2)"のように設定できます。 ng-clickのようなディレクティブを使用すると、このメカニズムを使用して、ディレクティブに渡される式の中の$event識別子を介してclickイベントにアクセスできます。

このソリューションでは、callbackを独立スコープのメンバーにする必要はありません。

15
lex82

私のために以下がうまくいった:

ディレクティブで次のように宣言します。

.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>

あなたはその宣言によって関数を渡し、それはディレクティブから呼び出され、パラメータが移入されます。

0
jabko87