3

ボタンを作成するためのangular.jsディレクティブがあります(ホバークラス、左右のアイコンなど)。ボタンの左アイコンと右アイコンの自動バインドを使用して、scope: { uiButtonIconLeft: '@', uiButtonIconRight: '@' }これらの値を親スコープのデータにバインドできるようにしています。ただし、これにより、angularjsは「分離」スコープを作成します。つまり、次のような状況でディレクティブを使用しても機能しません。

<div ng-controller='someController'>
    <a ng-repeat='thing in things'
       ui-button
       ui-button-icon-left='{{thing.icon}}'
       ng-click='someMethodTheControllerPutOnTheScope(thing.id)'
       >
       I don't work, don't bother clicking me
    </a>
</div>

代わりに、これを行う必要があります。

<div ng-controller='someController'>
    <a ng-repeat='thing in things'
       ui-button
       ui-button-icon-left='{{thing.icon}}'
       ng-click='$parent.someMethodTheControllerPutOnTheScope($parent.thing.id)'
       >
       Holy leaky abstractions, Batman, it works!
    </a>
</div>

私の質問は:これは慣用的なものですか?このようにすべきですか?私はそれを間違っていますか?私たちのヒーローは、マークアップの余分な、反復的な、迷惑な余分なものを一掃できます$parent.<whatever>か?

編集

attributes.$observe(...)私がボタン「ウィジェット」に決めた答えは、分離スコープの使用を避け、スコープを介してバインドするのではなく、を介して左右のアイコンの属性値を監視することです。

4

4 に答える 4

10

明示的なスコープを使用せずにそれを行う方法があります。スコープ内の要素を専用に処理しないディレクティブを作成している場合は、次のようにすることをお勧めします。

function MyDirective () {
    return {
        link: function (scope, iElement, iAttrs) {
            iAttrs.$observe("uiButtonLeft", function (val) {
                if (val) {
                    iElement.attr(src, val); // whatever you want to do
                }
            });
        }

}

<img ui-button ui-button-left="{{item.leftBtn}}"></img>

また{{val}}、クリーンなコードの場合、またはを変更したい場合は、使用が面倒になることがありますval。これがあなたがそれをする方法です。

function MyDirective () {
    return {
        link: function (scope, iElement, iAttrs) {
            iAttrs.$observe("uiButtonLeft", function (val) {
                scope.$watch(val, function (valInScope) {
                    if (valInScope) {
                        iElement.attr(src, valInScope); // whatever you want to do

                        // the following statement updates the value in scope
                        // it's kinda weird, but it works.
                        scope.$apply(val + "= Hello"); // if you are out of angularjs, like jquery event
                        scope.$eval(val + = "Hello"); // if you are in angualrjs
                        // $apply can handle string, it's like ngClick
                        // you use in templates. It updates the value correctly.
                    }
                }
            });
        }

}

<img ui-button ui-button-left="item.leftBtn"></img>
于 2013-02-13T17:25:03.790 に答える
5

@ローカルスコーププロパティにのみ適用されます。代わりに試してください&。これにより、親スコープのコンテキストで式を実行できます。

http://docs.angularjs.org/guide/directiveからの引用

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

John Lindquistは、彼のサイトegghead.ioビデオの17、18、および19でこれをうまくカバーしています。

于 2013-02-13T17:01:29.257 に答える
2

ディレクティブで分離スコープを使用する場合、およびHTML /マークアップの同じ要素から親/コントローラースコープで定義されたメソッドを呼び出す場合は、$parentを使用しても問題ありません。

通常、ng-repeatは通常、親/コントローラースコープからプロトタイプ的に継承する子スコープを作成するため、ng-repeat内で$parentを使用する必要はありません。したがって、ng-repeat内でメソッドを呼び出すと、プロトタイプチェーンをたどって親スコープに到達し、メソッドが検索されます。

ディレクティブは分離スコープを作成するため、各ng-repeat反復は、同じ要素で定義されているため、通常使用するスコープではなく、同じ分離スコープを使用するように強制されます。(HTMLから)親スコープで定義されたメソッドにアクセスする唯一の方法は、分離スコープから追跡するプロトタイプチェーンがないため、$parentを使用することです。

私たちが作成するカスタムディレクティブは、作成されるスコープの種類を文書化する必要があります。たとえば、Angularのドキュメントには、どのディレクティブが新しい​​スコープを作成するかが示されています。これに関するもう少し議論については、この回答のコメントを参照してください:https ://stackoverflow.com/a/14345214/215945

もう1つのオプションは、分離スコープを使用しないようにディレクティブを変更し、属性を使用して、ディレクティブが検査するスコーププロパティを示すことです。

于 2013-02-13T18:14:04.000 に答える
2

私はあなたが何をしようとしているのか理解していると思います。ディレクティブでは、ng-click属性を使用して、親に必要な関数にマップするように分離スコープを構成するだけです。

scope: {
    uiButtonIconLeft: '@',
    uiButtonIconRight: '@',
    clicky: '&ngClick'
}
于 2013-02-13T17:02:24.100 に答える