web-dev-qa-db-fra.com

Liaison des entrées à un tableau de primitives à l'aide de ngRepeat => entrées non modifiables

Voici une démo à mon problème.

$scope.myNumbers = [10, 20, 30];

<div ng-repeat="num in myNumbers">
    <input type="text" ng-model="num">
    <div>current scope: {{num}}</div>
</div>

Quelqu'un peut-il m'expliquer pourquoi les entrées ne sont pas modifiables/en lecture seule? Si c'est par conception, quelle est la justification derrière?

MISE À JOUR 20/02/2014

Il semble que ce ne soit plus un problème pour v1.2.0 + Demo . Mais gardez à l'esprit que bien que les contrôles utilisateur soient désormais modifiables avec les nouvelles versions angularJS, il s'agit de la propriété num dans la scopes enfants = , pas la portée parent, qui est modifiée. En d'autres termes, la modification des valeurs dans les contrôles utilisateur n'affecte pas le tableau myNumbers.

41
tamakisquare

Quelqu'un peut-il m'expliquer pourquoi les entrées ne sont pas modifiables/en lecture seule? Si c'est par conception, quelle est la justification derrière?

C'est par conception, à partir de Angular 1.0. . Artem a un très bonne explication de la façon dont 1.0.3+ fonctionne lorsque vous "lier à chaque élément ng-repeat directement" - c'est-à-dire,

<div ng-repeat="num in myNumbers">
  <input type="text" ng-model="num">

Lorsque votre page s'affiche initialement, voici une image de vos étendues (j'ai supprimé l'un des éléments du tableau, de sorte que l'image aurait moins de cases):

enter image description here (cliquez pour agrandir)

Les lignes pointillées montrent l'héritage de portée prototypique.
Les lignes grises montrent les relations enfant → parent (c'est-à-dire, ce que $parent les références).
Les lignes brunes indiquent $$ nextSibling.
Les cases grises sont des valeurs primitives. Les cases bleues sont des tableaux. Le violet sont des objets.

Notez que la réponse SO que j'ai référencée dans un commentaire a été écrite avant la sortie de 1.0.3. Avant 1.0.3, les valeurs num dans les étendues enfants ngRepeat seraient changent réellement lorsque vous tapez dans les zones de texte. (Ces valeurs ne seraient pas visibles dans la portée parent.) Depuis 1.0.3, ngRepeat remplace maintenant les valeurs ngRepeat scope num par les valeurs (inchangées) du parent Le tableau myNumbers de la portée/MainCtrl pendant un cycle de résumé, ce qui rend essentiellement les entrées non modifiables.

Le correctif consiste à utiliser un tableau d'objets dans votre MainCtrl:

$scope.myNumbers = [ {value: 10}, {value: 20} ];

puis liez à la propriété value de l'objet dans le ngRepeat:

<div ng-repeat="num in myNumbers">
  <input type="text" ng-model="num.value">
  <div>current scope: {{num.value}}</div>
67
Mark Rajcok

Ce problème est désormais résolu par les versions plus récentes d'AngularJS avec le track by fonctionnalité permettant aux répéteurs de remplacer les primitives:

<div ng-repeat="num in myNumbers track by $index">
  <input type="text" ng-model="myNumbers[$index]">
</div>

La page ne sera pas repeinte après chaque frappe, ce qui résout le problème de la perte de focus. Le document officiel d'AngularJS est assez vague et déroutant à ce sujet.

33
sebnukem

J'ai eu un problème similaire (et j'avais également besoin des fonctionnalités "ajouter" et "supprimer"), et j'ai résolu le problème comme suit:

$scope.topics = [''];
$scope.removeTopic = function(i) {
   $scope.topics.splice(i, 1); 
}

<div ng-repeat="s in topics track by $index">
    <input ng-model="$parent.topics[$index]" type="text">
    <a ng-click="removeTopic($index)">Remove</a>
</div>

<a ng-click="topics.Push('new topic')">Add</a>
9
aidan

ngRepeat utilise une référence au tableau source. Puisque integer (Number in js) est un type de valeur , pas une référence , ne peut donc pas être transmis par référence en javascript. Le changement ne sera pas propagé.

Voici une démonstration:

   var x = 10;
   var ox = {value:10};

   var y = x;
   var oy = ox;

   y = 15
   oy.value = 15;

Quelles seraient les valeurs de x et ox?

>> x = 10;
>> y = 15;
>> ox = {value:15};
>> oy = {value:15};

Tous les objets javascript sont passés par référence et toutes les primitives sont passées par valeur ["chaîne", "nombre", etc.].

Plunker de travail http://plnkr.co/edit/7uG2IvAdC2sAEHbdHG58

9
Umur Kontacı

Semble que Angular ne peut pas écrire dans le modèle défini de cette façon. Utilisez la référence à l'attribut initial $ scope pour lui permettre de lier la valeur correctement:

<div ng-repeat="num in myNumbers">
  <input type="text" ng-model="myNumbers[$index]">
</div>
9
Dmitry Evseev