95

分離スコープを使用したディレクティブがあり(他の場所でディレクティブを再利用できるようにするため)、このディレクティブを。で使用するとng-repeat、機能しません。

このトピックに関するすべてのドキュメントとStackOverflowの回答を読み、問題を理解しました。私はいつもの落とし穴をすべて避けたと思います。

ng-repeatしたがって、ディレクティブによって作成されたスコープが原因でコードが失敗することを理解しています。私自身のディレクティブは、分離スコープを作成し、親スコープ内のオブジェクトへの双方向のデータバインディングを実行します。私のディレクティブは、このバインドされた変数に新しいオブジェクト値を割り当てます。これは、私のディレクティブが使用されていない場合ng-repeat(親変数が正しく更新されている場合)に完全に機能します。ただし、を使用するng-repeatと、割り当てによってng-repeatスコープ内に新しい変数が作成され、親変数は変更を認識しません。これはすべて、私が読んだ内容に基づいて予想どおりです。

また、特定の要素に複数のディレクティブがある場合、1つのスコープのみが作成されることも読みました。またpriority、各ディレクティブにaを設定して、ディレクティブが適用される順序を定義できます。ディレクティブは優先度で並べ替えられ、コンパイル関数が呼び出されます( http://docs.angularjs.org/guide/directiveでpriorityという単語を検索してください)。

そのため、優先度を使用して、ディレクティブが最初に実行され、最終的に分離スコープが作成されるようにしたいと考えていましたng-repeat。実行すると、親スコープからプロトタイプを継承するスコープを作成する代わりに、分離スコープを再利用します。ng-repeatドキュメントには、そのディレクティブは優先度レベルで実行されると記載されています10001優先度が高いのか低いのかは明確ではありません。ディレクティブで優先度を使用した場合1、違いはなかったので、試してみ2000ました。しかし、それは事態をさらに悪化させます。私の双方向バインディングはになりundefined、私のディレクティブは何も表示しません。

私は自分の問題を示すためにフィドルを作成しました。priorityディレクティブの設定をコメントアウトしました。名前オブジェクトのリストと、名前オブジェクトの名前フィールドと名前フィールドを表示するというディレクティブがありname-rowます。selected表示されている名前をクリックすると、メインスコープに変数を設定してほしい。名前の配列である変数は、双方向のデータバインディングを使用selectedしてディレクティブに渡されます。name-row

メインスコープの関数を呼び出すことでこれを機能させる方法を知っています。selectedまた、別のオブジェクトの内側にあり、外側のオブジェクトにバインドすると、動作することもわかっています。しかし、私は現時点ではそれらの解決策には興味がありません。

代わりに、私が持っている質問は次のとおりです。

  • ng-repeat親スコープからプロトタイプ的に継承するスコープを作成せず、代わりにディレクティブの分離スコープを使用させるにはどうすればよいですか?
  • 2000ディレクティブの優先度が機能しないのはなぜですか?
  • Batarangを使用して、どのタイプのスコープが使用されているかを知ることは可能ですか?
4

2 に答える 2

203

さて、上記の多くのコメントを通して、私は混乱を発見しました。まず、いくつかの明確化のポイント:

  • ngRepeatは、選択した分離スコープには影響しません
  • ディレクティブの属性で使用するためにngRepeatに渡されるパラメーターは、プロトタイプで継承されたスコープを使用します
  • ディレクティブが機能しない理由は、分離スコープとは何の関係もありません

同じコードの例ですが、ディレクティブが削除されています。

<li ng-repeat="name in names"
    ng-class="{ active: $index == selected }"
    ng-click="selected = $index">
    {{$index}}: {{name.first}} {{name.last}}
</li>

これは、動作しないことを示すJSFiddleです。ディレクティブとまったく同じ結果が得られます。

なぜそれが機能しないのですか?AngularJSのスコープはプロトタイプの継承を使用するためです。selected親スコープの値はプリミティブです。JavaScriptでは、これは、子が同じ値を設定すると上書きされることを意味します。AngularJSスコープには黄金律があります。モデル値には常にが含ま.れている必要があります。つまり、それらはプリミティブであってはなりません。詳細については、このSOの回答を参照してください。


これは、スコープが最初にどのように見えるかの写真です。

ここに画像の説明を入力してください

最初の項目をクリックすると、スコープは次のようになります。

ここに画像の説明を入力してください

selectedngRepeatスコープに新しいプロパティが作成されたことに注意してください。コントローラスコープ003は変更されていません。

2番目の項目をクリックすると、おそらく何が起こるかを推測できます。

ここに画像の説明を入力してください


したがって、問題は実際にはngRepeatが原因ではなく、AngularJSの黄金律を破ることが原因です。これを修正する方法は、単にオブジェクトプロパティを使用することです。

$scope.state = { selected: undefined };
<li ng-repeat="name in names"
    ng-class="{ active: $index == state.selected }"
    ng-click="state.selected = $index">
    {{$index}}: {{name.first}} {{name.last}}
</li>

これもこれが機能することを示す2番目のJSFiddleです。

スコープが最初にどのように見えるかを次に示します。

ここに画像の説明を入力してください

最初の項目をクリックした後:

ここに画像の説明を入力してください

ここでは、必要に応じてコントローラースコープが影響を受けています。

また、これが分離スコープを使用するディレクティブで引き続き機能することを証明するために(これも問題とは関係がないため)、これもそのためのJSFiddleであり、ビューはオブジェクトを反映する必要があります。必要な変更は、プリミティブの代わりにオブジェクトを使用することだけであることに注意してください。

最初のスコープ:

ここに画像の説明を入力してください

最初の項目をクリックした後のスコープ:

ここに画像の説明を入力してください

結論として、繰り返しになりますが、問題は分離スコープにあるのではなく、ngRepeatの動作にあるのではありません。あなたの問題は、この非常に問題につながることが知られているルールを破っているということです。AngularJSのモデルには常に。が必要.です。

于 2013-03-26T19:06:14.937 に答える
6

質問に直接答えることを避けようとせずに、代わりに次のフィドルを見てください。

http://jsfiddle.net/dVPLM/

重要な点は、Angularの従来の動作と戦って変更しようとする代わりに、ディレクティブをng-repeatオーバーライドしようとするのではなく、動作するようにディレクティブを構造化できることです。

テンプレート内:

    <name-row 
        in-names-list="names"
        io-selected="selected">
    </name-row>

あなたの指令では:

    template:
'        <ul>' +      
'            <li ng-repeat="name in inNamesList" ng-class="activeClass($index)" >' +
'                <a ng-click="setSelected($index)">' +
'                    {{$index}} - {{name.first}} {{name.last}}' +
'                </a>' +
'            </li>' +
'        </ul>'

あなたの質問に答えて:

于 2013-03-25T20:34:26.170 に答える