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


160

特定のcallback属性を分離スコープで使用するフォームディレクティブがあります。

scope: { callback: '&' }

それは内部にあるng-repeatので、私が渡す式にはid、コールバック関数への引数としてオブジェクトのが含まれています。

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

ディレクティブを使い終えると、$scope.callback()コントローラー関数から呼び出されます。ほとんどの場合、これで問題ありませんし、やりたいことはこれだけですが、場合によっては、directiveそれ自体の内部から別の引数を追加したいこともあります。

これを可能にする角度式はありますか:$scope.callback(arg2)callbackで呼び出されarguments = [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]) );

しかし、私はそれが特にきちんとしているとは思いません、それは分離スコープに余分なものを置くことを含みます。

もっと良い方法はありますか?

ここにプランカー遊び場があります(コンソールを開いたままにします)。


「callback = "という名前の属性は誤解を招きます。これは実際にはコールバックの評価であり、コールバック自体ではありません。
ドミトリザイツェフ2015年

@DmitriZaitsevこれは、JavaScript関数に評価されるコールバック角度式です。それ自体がJavaScript関数ではないことは明らかです。それは単なる好みですが、すべての属性の末尾に「-式」を付ける必要はありません。これは、ngAPI と一致しています。たとえばng-click="someFunction()"、関数の実行を評価する式です。
Ed Hinchliffe、2015年

「コールバック」と呼ばれる角度表現を見たことがありません。これは常に、名前を呼び出すために渡す関数です。例では「コールバック」と呼ばれる関数を使用して、事態をさらに混乱させています。
ドミトリザイツェフ2015年

あなたが混乱しているかどうか、私はわかりません。私の例で$scope.callbackは、ディレクティブ定義オブジェクトのcallback="someFunction"属性とscope: { callback: '=' }プロパティによって設定されています。$scope.callback 後日呼び出される関数は。実際の属性は明らかに文字列です-これは常にHTMLの場合です。
Ed Hinchliffe、2015年

属性と機能の両方に同じ名前を付けます-「コールバック」。それが混乱のレシピです。本当に避けやすい。
ドミトリザイツェフ2015年

回答:


215

@ lex82で述べられているようにコールバックを宣言すると

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

オブジェクトマップを使用してディレクティブスコープのコールバックメソッドを呼び出すと、バインディングが正しく行われます。お気に入り

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

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

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

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


4
非常に素晴らしい!これはどこかに文書化されていますか?
2014年

12
私は時々 、あなたが渡すためのパラメータに何か分からないでしょう、なぜならディレクティブの定義では、それは良い解決策だと思ういけない。
OMGPOP

これは良い解決策であり、ありがとうございましたが、答えには少し手を加える必要があると思います。lex82とは誰ですか?彼は何を述べましたか?
Wtower 2016

興味深いアプローチ。ANYパラメータ(または複数)を持つ関数を渡せるようにするとどうなりますか?関数もそのパラメーターも知らず、ディレクティブ内のイベントで実行する必要があります。それについてどうやって行くのですか?たとえば、ディレクティブでは、onchangefunc = 'myCtrlFunc(dynamicVariableHere)'
trainoasis

58

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

ディレクティブを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); 

他の入れ子のシナリオでは失敗します。

Dan Wahlinの優れた記事(http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-3-isolate-scope-and-function-parameters)からこの手法を採用しました

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


2
素晴らしいアプローチですがthis、ディレクティブのスコープを使用するため、コールバックメソッド内でポインターを使用できません。:私はこのような活字体と私のコールバックのルックスを使用していますpublic validateFirstName(firstName: string, fieldName: string): ng.IPromise<boolean> { var deferred = this.mQService.defer<boolean>(); ... .then(() => deferred.resolve(true)) .catch((msg) => { deferred.reject(false); }); return deferred.promise; }
ndee

1
通知:ネストされたディレクティブがあり、コールバックを上方に伝播したい場合、1つのトリガーコールバックだけでなく、各ディレクティブでラップ解除する必要があります。
Episodex 2015

43

ディレクティブ(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)'>の場合、次に進む方法は?
Ankit Pandey

15

はい、より良い方法があります。ディレクティブの$ parseサービスを使用して、親スコープのコンテキストで式を評価し、式の特定の識別子をディレクティブ内でのみ表示される値にバインドできます。

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

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

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

callbackこのソリューションでは、孤立したスコープのメンバーを作成する必要がないことに注意してください。


3
を使用scope.$parentすると、ディレクティブが「漏洩」します。適切に設計されたカプセル化されたコンポーネントがそれを行うべきではない、外界を過剰に「認識」します。
Dmitri Zaitsev 2015

3
まあ、それは親スコープがあることを知っていますが、スコープ内の特定のフィールドにアクセスしないので、これは許容できると思います。
lex82、2015

0

私のために働いた:

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.