web-dev-qa-db-fra.com

Difficulté avec ng-model, ng-repeat et input

J'essaie de permettre à l'utilisateur de modifier une liste d'éléments en utilisant ngRepeat et ngModel. ( Voir ce violon .) Cependant, les deux approches que j'ai essayées conduisent à un comportement bizarre: l'une ne met pas à jour le modèle et l'autre rend la forme floue sur chaque touche du bas.

Est-ce que je fais quelque chose de mal ici? N'est-ce pas un cas d'utilisation pris en charge?

Voici le code du violon, copié pour plus de commodité:

<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>

Un séjour sans faille

115
Nick Heiner

Cela semble être un problème contraignant.

Le conseil est ne pas lier aux primitives .

Votre ngRepeat effectue une itération sur les chaînes d'une collection, alors qu'elle devrait itérer sur des objets. Pour résoudre votre problème

<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/

120
jaime

En utilisant Angular dernière version (1.2.1) et en suivant $index. Ce problème est résolu

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

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

Vous entrez dans une situation difficile lorsqu'il est nécessaire de comprendre comment scopes , ngRepeat et ngModel avec NgModelController . Essayez également d'utiliser la version 1.0.3. Votre exemple fonctionnera un peu différemment.

Vous pouvez simplement utiliser la solution fournie par jm-

Mais si vous voulez traiter la situation plus profondément, vous devez comprendre:

  • comment fonctionne AngularJS ;
  • les portées ont une structure hiérarchique;
  • ngRepeat crée une nouvelle portée pour chaque élément;
  • ngRepeat construire le cache des éléments avec des informations supplémentaires (hashKey); à chaque appel de surveillance pour chaque nouvel élément (qui n'est pas dans le cache), ngRepeat construit une nouvelle portée, un élément DOM, etc. Description plus détaillée .
  • à partir de 1.0.3 ngModelController rentre des entrées avec les valeurs réelles du modèle.

Comment votre exemple "Lier directement à chaque élément" fonctionne pour AngularJS 1.0.3:

  • vous entrez la lettre 'f' en entrée;
  • ngModelController modifie le modèle pour la portée de l'élément (le tableau de noms n'est pas modifié) => name == 'Samf', names == ['Sam', 'Harry', 'Sally'];
  • La boucle $digest est lancée;
  • ngRepeat remplace la valeur du modèle de la portée de l'élément ('Samf') par la valeur du tableau des noms inchangés ('Sam');
  • ngModelController render les entrées avec la valeur réelle du modèle ('Sam').

Comment votre exemple "Indexation dans le tableau" fonctionne:

  • vous entrez la lettre 'f' en entrée;
  • ngModelController change l'élément dans les noms array => `noms == ['Samf', 'Harry', 'Sally'];
  • La boucle $ digérer est démarrée;
  • ngRepeat ne trouve pas 'Samf' dans le cache;
  • ngRepeat crée une nouvelle portée, ajoute un nouvel élément div avec une nouvelle entrée (c’est pourquoi le champ d’entrée perd son focus - l’ancien div avec l’ancienne entrée est remplacé par un nouveau div avec une nouvelle entrée);
  • les nouvelles valeurs pour les nouveaux éléments DOM sont rendues.

En outre, vous pouvez essayer d'utiliser AngularJS Batarang et voir comment modifie $ id de l'étendue de div avec l'entrée dans laquelle vous entrez.

43
Artem Andreev

Si vous n'avez pas besoin que le modèle soit mis à jour à chaque frappe de touche, liez-vous simplement à name, puis mettez à jour l'élément de tableau lors de l'événement de flou:

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

Je viens de mettre à jour AngularJs à 1.1.2 et je n’ai aucun problème avec ça. Je suppose que ce bug a été corrigé.

http://ci.angularjs.org/job/angular.js-pete/57/artifact/build/angular.js

4
Anton Rodin

Le problème semble être lié à la façon dont ng-model fonctionne avec input et écrase l'objet name, le rendant ainsi perdu pour ng-repeat.

Pour contourner le problème, vous pouvez utiliser le code suivant:

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

J'espère que ça aide

2
Draško Kokić

J'ai essayé la solution ci-dessus pour mon problème à cela a fonctionné comme un charme. Merci!

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

Voici ma version de cela:

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

}

et mon HTML

<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>
1
Leigh Lawhon