私は AngularJS を学習しており、ユーザーが多くの入力を行えるようにしたいと考えています。これらの入力が入力されると、list
配列要素がそれに応じて変更される必要があります。ngRepeat ディレクティブを使用してみたかったのですが、新しいスコープが作成されるため、データバインドできないと読みました。
<div ng-repeat="item in list">
<label>Input {{$index+1}}:</label>
<input ng-model="item" type="text"/>
</div>
これを行うにはカスタム ディレクティブを使用する必要があるのか、それとも別の方法でアプローチする必要があるのか疑問に思っていました。
ベストアンサー1
プリミティブな「アイテム」へのデータバインディングが機能しない理由は、ng-repeat が各アイテムの子スコープを作成する方法によるものです。各アイテムについて、ng-repeat は新しい子スコープをプロトタイプ的に親スコープから継承します (下の図の破線を参照)。その後アイテムの値を子スコープの新しいプロパティに割り当てます(下の図の赤いアイテム)。新しいプロパティの名前はループ変数の名前です。ng-repeat ソースコード:
childScope = scope.$new();
...
childScope[valueIdent] = value;
アイテムがプリミティブの場合、新しい子スコーププロパティには基本的にプリミティブの値のコピーが割り当てられます。この子スコーププロパティは親スコープからは見えず、入力フィールドに加えた変更はこの子スコーププロパティに保存されます。たとえば、親スコープに
$scope.list = [ 'value 1', 'value 2', 'value 3' ];
HTML では次のようになります:
<div ng-repeat="item in list">
item
すると、最初の子スコープには、プリミティブ値 ( value 1
)を持つ次のプロパティが設定されます。
item: "value 1"
ng-model データバインディングにより、フォームの入力フィールドに加えた変更はその子スコープ プロパティに保存されます。
これを確認するには、子スコープをコンソールに記録します。HTML の ng-repeat 内に以下を追加します。
<a ng-click="showScope($event)">show scope</a>
コントローラーに追加:
$scope.showScope = function(e) {
console.log(angular.element(e.srcElement).scope());
}
@Gloopy のアプローチでは、各子スコープは引き続き新しい「item」プロパティを取得しますが、リストはオブジェクトの配列になったため、
childScope[valueIdent] = value;
item プロパティの値は配列オブジェクトの 1 つへの参照 (コピーではない) に設定されます。
showScope() テクニックを使用すると、子スコープitem
プロパティの値が配列オブジェクトの 1 つを参照していることがわかります。これはもはやプリミティブ値ではありません。
参照ng-repeat 子スコープ内のプリミティブにバインドしないそして
AngularJS のスコープ プロトタイプ / プロトタイプ継承のニュアンスは何ですか?(ng-repeat を使用した場合のスコープの外観を示す画像が含まれています)。