Ng-modeli, ng-tekrarı ve girdilerle ilgili zorluk


116

Ben kullanarak düzenlemek için kullanıcıya öğelerin listesini izin çalışıyorum ngRepeatve ngModel. ( Bakın bu keman .) Bununla birlikte, denediğim her iki yaklaşım da tuhaf davranışlara yol açıyor: biri modeli güncellemiyor, diğeri ise her tuş basışında formu bulanıklaştırıyor.

Burada yanlış bir şey mi yapıyorum? Bu, desteklenen bir kullanım durumu değil mi?

İşte size kolaylık sağlamak için kopyalanmış keman kodudur:

<html ng-app>
    <head>
        <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/css/bootstrap-combined.min.css" rel="stylesheet">
    </head>
    <body ng-init="names = ['Sam', 'Harry', 'Sally']">
        <h1>Fun with Fields and ngModel</h1>
        <p>names: {{names}}</p>
        <h3>Binding to each element directly:</h3>
        <div ng-repeat="name in names">
            Value: {{name}}
            <input ng-model="name">                         
        </div>
        <p class="muted">The binding does not appear to be working: the value in the model is not changed.</p>
        <h3>Indexing into the array:</h3>
        <div ng-repeat="name in names">
            Value: {{names[$index]}}
            <input ng-model="names[$index]">                         
        </div>
        <p class="muted">Type one character, and the input field loses focus. However, the binding appears to be working correctly.</p>
    </body>
</html>


1
Bu, stackoverflow.com/questions/12977894/… 'e çok benzer , ancak 2. yaklaşım burada yenidir, bu nedenle tam olarak bir kopya değildir. Burada, tekrarlayan çocuk kapsamlarının nasıl çalıştığını açıklayan ayrıntılı bir cevap (Artem'inkine benzer) verdim.
Mark Rajcok

Sonunda bu konuyu bulmadan önce bana makul miktarda Google'da arama yapmaya mal olduğu için, "Ana Model ngRepeat girişlerinden güncellenmedi" veya "ngRepeat kullanılırken model güncellenmedi" veya "ngRepeat girişleri bağlı değil (ana) gibi bir şekilde yeniden adlandırabilir miyim? "modeli? Belki başlık için daha iyi fikirleriniz var?
vucalur

Yanıtlar:


120

Bu bağlayıcı bir konu gibi görünüyor.

Tavsiye, ilkellere bağlamamaktır .

Sizin ngRepeato nesnelerin üzerine iterating olması gerekirken, kolleksiyon içindeki dizeleri yineleme edilir. Problemini çözmek için

<body ng-init="models = [{name:'Sam'},{name:'Harry'},{name:'Sally'}]">
    <h1>Fun with Fields and ngModel</h1>
    <p>names: {{models}}</p>
    <h3>Binding to each element directly:</h3>
    <div ng-repeat="model in models">
        Value: {{model.name}}
        <input ng-model="model.name">                         
    </div>

jsfiddle: http://jsfiddle.net/jaimem/rnw3u/5/


3
Bulanıklık / odak kaybı / titreme sorununu açıkladığından ilk köprü için teşekkürler. Bunun neden olduğunu hep merak etmişimdir.
Mark Rajcok

2
bunun için teşekkürler, çok yardımcı oldu. Yine de, ilkellere bağlanma imo olmalı ...
Daniel Gruszczyk

1
eski gönderi ama thnx, 'ngRepeat içindeki modeli değiştirmeme' sorununu bulmam biraz zaman aldı ve ilkellere bağlanmama tavsiyen oldu
Stefanos Chrs

Ayrıca: Yazarken tüm listeyi değiştirmeyin - düştüğüm bir tuzak. Koleksiyonu değişiklikler için izliyordum ve onu aynı kopya ile değiştiriyordum - bu yüzden ilkellere bağlı olmasam da öğeler yeniden yaratılıyordu.
z0r

71

Angular en son sürümü (1.2.1) kullanarak ve $index. Bu sorun düzeltildi

http://jsfiddle.net/rnw3u/53/

<div ng-repeat="(i, name) in names track by $index">
    Value: {{name}}
    <input ng-model="names[i]">                         
</div>

işi yaptı; artık referans kaybı yok
Dan Ochiana

Bunun için çok uzun zamandır aradım .... çok kolay ... sadece çok gizli. Bunu cevap olarak ver!
Andrea

oooooh, bu yüzden ng-
tekrar'a

43

NgModelController ile kapsamların , ngRepeat ve ngModel'in nasıl çalıştığını anlamak gerektiğinde zor bir duruma düşersiniz . Ayrıca 1.0.3 sürümünü kullanmayı deneyin. Örneğiniz biraz farklı çalışacaktır.

Jm tarafından sağlanan çözümü basitçe kullanabilirsiniz.

Ancak durumla daha derinlemesine ilgilenmek istiyorsanız, anlamalısınız:

  • AngularJS nasıl çalışır ;
  • kapsamlar hiyerarşik bir yapıya sahiptir;
  • ngRepeat, her öğe için yeni kapsam oluşturur;
  • ngRepeat, ek bilgiler içeren öğelerin önbelleğini (hashKey) oluşturma; her saatte her yeni öğe için çağrı (önbellekte olmayan) ngRepeat yeni kapsam, DOM öğesi, vb . oluşturur . Daha ayrıntılı açıklama .
  • 1.0.3 ngModelController'den itibaren, girdileri gerçek model değerleriyle yeniden gönderir.

"Her öğeye doğrudan bağlanma" örneğiniz AngularJS 1.0.3 için nasıl çalışır?

  • 'f'girişe harf girersiniz ;
  • ngModelControlleret kapsamı modeli değiştirir (isimler dizi değiştirilmez) => name == 'Samf', names == ['Sam', 'Harry', 'Sally'];
  • $digest döngü başlatılır;
  • ngRepeatöğe kapsamındaki ( 'Samf') model değerini değiştirilmemiş adlardaki değerle değiştirir array ( 'Sam');
  • ngModelControllergirdiyi gerçek model değeri ( 'Sam') ile yeniden işler .

"Dizinin indekslenmesi" örneğiniz nasıl çalışır:

  • 'f'girişe harf girersiniz ;
  • ngModelControllerisimlerdeki öğeyi değiştirir array=> `isimler == ['Samf', 'Harry', 'Sally'];
  • $ özet döngüsü başlatıldı;
  • ngRepeat'Samf'önbellekte bulunamıyor ;
  • ngRepeat yeni kapsam oluşturur, yeni girişle yeni div öğesi ekler (bu nedenle giriş alanı odağı kaybeder - eski girişli eski div, yeni girişli yeni div ile değiştirilir);
  • yeni DOM öğeleri için yeni değerler oluşturulur.

Ayrıca, AngularJS Batarang'ı kullanmayı deneyebilir ve girdiğiniz girdi ile div kapsamının $ id'nin nasıl değiştiğini görebilirsiniz.


1.0.3 açıklaması için teşekkürler. İlginçtir ki, 1.0.3'te, "doğrudan bağlan" durumunda, giriş alanı, herhangi bir değişikliği / yazılan girişi kabul etmiyor gibi görünmesi açısından (en azından Chrome'da) bozuk görünmektedir. Eminim yakın gelecekte bununla ilgili epeyce SO gönderi göreceğiz :) Sanırım bu yeni yol daha iyi, çünkü bir şeylerin yanlış olduğu daha aşikar olacak.
Mark Rajcok

6

Her tuş vuruşunda modelin güncellenmesine ihtiyacınız yoksa, sadece bağlanın nameve ardından bulanıklaştırma olayında dizi öğesini güncelleyin:

<div ng-repeat="name in names">
    Value: {{name}}
    <input ng-model="name" ng-blur="names[$index] = name" />
</div>

Why not using ng-model="names[$index]" ... I know it's a workaround, but it works ;-)
Draško Kokić


2

Sorun , nesnenin nasıl ng-modelçalıştığı inputve namenesnenin üzerine yazarak onu kaybetme biçiminde görünüyor ng-repeat.

Geçici bir çözüm olarak, aşağıdaki kod kullanılabilir:

<div ng-repeat="name in names">
    Value: {{name}}
    <input ng-model="names[$index]">                         
</div>

Umarım yardımcı olur


1

Sorunum için yukarıdaki çözümü denedim, harika çalıştı. Teşekkürler!

http://jsfiddle.net/leighboone/wn9Ym/7/

İşte benim versiyonum:

var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
    $scope.models = [{
        name: 'Device1',
        checked: true
    }, {
        name: 'Device1',
        checked: true
    }, {
        name: 'Device1',
        checked: true
    }];

}

ve benim HTML’im

<div ng-app="myApp">
    <div ng-controller="MyCtrl">
         <h1>Fun with Fields and ngModel</h1>
        <p>names: {{models}}</p>
        <table class="table table-striped">
            <thead>
                <tr>
                    <th></th>
                    <th>Feature 1</td>
                    <th>Feature 2</th>
                    <th>Feature 3</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Device</td>
                   <td ng-repeat="modelCheck in models" class=""> <span>
                                    {{modelCheck.checked}}
                                </span>

                    </td>
                </tr>
                <tr>
                    <td>
                        <label class="control-label">Which devices?</label>
                    </td>
                    <td ng-repeat="model in models">{{model.name}}
                        <input type="checkbox" class="checkbox inline" ng-model="model.checked" />
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</div>

-5

şöyle bir şey nasıl yapılır:

<select ng-model="myModel($index+1)">

Ve müfettiş unsurumda:

<select ng-model="myModel1">
...
<select ng-model="myModel2">
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.