31

私はangularjsを学んでおり、ユーザーが多くの入力を入力できるようにしたいと考えています。これらの入力を入力すると、listそれに応じて配列要素が変更されます。ngRepeatディレクティブを使用してみたかったのですが、新しいスコープが作成されるため、データバインドできません。

<div ng-repeat="item in list">
    <label>Input {{$index+1}}:</label>
    <input ng-model="item" type="text"/>
</div>

これを行うためにカスタムディレクティブを使用するべきか、それとも別の方法でアプローチするべきか疑問に思いました。

4

5 に答える 5

88

プリミティブ「アイテム」へのデータバインディングが機能しない理由は、ng-repeatが各アイテムの子スコープを作成する方法のためです。アイテムごとに、ng-repeatは親スコープからプロトタイプ的に継承する新しい子スコープを持ち(下の図の破線を参照)、次にアイテムの値を子スコープの新しいプロパティ(下の図の赤いアイテム)に割り当てます。新しいプロパティの名前は、ループ変数の名前です。ng-repeatソースコードから:

childScope = scope.$new();
...
childScope[valueIdent] = value;

itemがプリミティブの場合、新しい子スコーププロパティには、基本的にプリミティブの値のコピーが割り当てられます。この子スコーププロパティは親スコープには表示されず、入力フィールドに加えた変更はこの子スコーププロパティに保存されます。たとえば、親スコープにあるとします

$scope.list = [ 'value 1', 'value 2', 'value 3' ];

そしてHTMLで:

<div ng-repeat="item in list">

次に、最初の子スコープはitem、プリミティブ値(value 1)を持つ次のプロパティを持ちます。

item: "value 1"

ng-プリミティブで繰り返す

ng-modelデータバインディングにより、フォームの入力フィールドに加えた変更は、その子スコーププロパティに保存されます。

これは、子スコープをコンソールに記録することで確認できます。ng-repeat内のHTMLに追加します。

<a ng-click="showScope($event)">show scope</a>

コントローラに追加します:

$scope.showScope = function(e) {
    console.log(angular.element(e.srcElement).scope());
}


@Gloopyのアプローチでは、各子スコープは引き続き新しい「item」プロパティを取得しますが、listはオブジェクトの配列になっているためchildScope[valueIdent] = value;、itemプロパティの値は配列オブジェクトの1つ(コピーではない)への参照に設定されます。

ng-オブジェクトで繰り返す

showScope()手法を使用すると、子スコープitemプロパティの値が配列オブジェクトの1つを参照していることがわかります。これは、プリミティブ値ではなくなりました。

ng-repeat子スコープのプリミティブにバインドしないおよび
AngularJSのスコープのプロトタイプ/プロトタイプ継承のニュアンスは何ですか?も参照してください。(これには、ng-repeatを使用した場合のスコープの外観の写真が含まれています)。

于 2012-12-08T22:40:36.207 に答える
37

listがオブジェクトの配列である場合(プリミティブの配列ではなく)、運が良くなります。これは、次のコマンドで新しいスコープが作成された場合でも正常に機能しng-repeatます。

<div ng-repeat="item in list">
    <label>Input {{$index+1}}:</label>
    <input ng-model="item.value" type="text"/>
</div>

次のコントローラーを使用:

function TestController($scope) {
    $scope.list = [ { value: 'value 1' }, { value: 'value 2' }, { value: 'value 3' } ];
}​

例としてこのフィドルを参照してください。

一方、文字列の配列にバインドしようとすると、変更する値が元の配列文字列プリミティブに関連付けられないため、新しいスコープで問題が発生します(このフィドルの例のように)。

于 2012-10-19T15:57:18.680 に答える
3

これを行うための興味深い方法を見つけました。これにより、プリミティブの配列で作業できるようになりました。

私はAngularJS1.2.1を使用しています。これは、これを機能させることができる唯一のバージョンです。

HTML:

<div ng-repeat="item in list">
    <label>Input {{$index+1}}:</label>
    <input ng-model="item" type="text" ng-blur="editItem($index, item)"/>
</div>

JavaScript:

$scope.editItem = function(idx, eItem) {
    $scope.list[idx] = eItem;
};

リンク: http: //jsfiddle.net/bxD2P/10/(スターターFiddleを提供してくれたGloopyに感謝します)

これがどのように機能するかに穴を開ける簡単な方法があると確信しています、そして私はそれらを聞いてみたいです。それは私が私のコードを強化することを可能にするでしょう。

于 2014-10-09T17:50:24.543 に答える
1

これを行う方法は次のとおりです。textareasとリピーターとは異なる構造を使用しましたが、主な概念は次のとおりです。

  • インデックスに基づいて単純な値を表示します。(バインドされていません)
  • ぼかし時にモデルを更新
  • モデル更新時の再レンダリング

それは本質的に、バインディングを偽造しています。

ワーキングフィドル-http://jsfiddle.net/VvnWY/4/

html:

  <script type="text/ng-template" id="textareas.html">
    <textarea ng-if="strings" ng-repeat="str in strings" ng-blur="blur( $event, $index )">{{strings[$index]}}</textarea>
  </script>

<div ng-controller="MyCtrl">
    Here's a few strings: <br />
    <div ng-repeat="str in strings">{{strings[$index]}}</div>

    Here's the strings as editable (twice so that you can see the updates from a model change): <br />
    <form-textareas strings="strings"></form-textareas>
    <form-textareas strings="strings"></form-textareas>

</div>

JS:

var myApp = angular.module('myApp',[]);
angular.module('myApp', [])
  .controller('MyCtrl', ['$scope', function($scope) {
    $scope.strings = [ "foo", "bar", "cow" ];
   }])
  .directive('formTextareas', function() {
    return {
        restrict: "E",
        scope: {
            strings: '='
        },
        templateUrl: "textareas.html",
        link: function( $scope ){
            $scope.blur = function( $event, $index ){
                $scope.strings[ $index ] = $event.currentTarget.value;
            };
        }
    };
  })
;
于 2014-04-12T21:22:49.750 に答える
1

ngListディレクティブhttps://docs.angularjs.org/api/ng/directive/ngListの使用を検討してください

于 2014-04-24T11:16:31.240 に答える