web-dev-qa-db-fra.com

Angularjs: sélectionne pas de mise à jour lorsque ng-model est mis à jour

J'ai créé l'exemple suivant pour que vous puissiez voir exactement ce qui se passe: http://jsfiddle.net/8t2Ln/101/

La même chose se produit si j'utilise ng-options. J'ai une raison différente de le faire de cette façon, mais la simplification de l'exemple l'a laissée de côté.

Comme vous pouvez le voir, il a deux options par défaut. J'affiche la valeur sélectionnée du modèle-ng à côté de la sélection afin que vous puissiez voir ce que c'est. Lorsque vous utilisez la pièce du haut pour ajouter une troisième option, la valeur de cette nouvelle option est définie comme indiqué par la valeur du modèle ng affichée à côté de la sélection, mais la sélection elle-même ne change pas pour afficher la valeur correcte. choisi.

Voici l'exemple de code sur le lien:

var testApp = angular.module('testApp', ['ngRoute']);

testApp.controller('Ctrl', function ($scope) {

    $scope.newInput = '';
    $scope.inputDevice = [
        {
            value: '1',
            label: 'input1'
        },
        {
            value: '2',
            label: 'input2'
        }
    ];
    $scope.selectedDevice = '';

    $scope.addType = function () {
        var newElem = {
            label: $scope.newInput,
            value: '3'
        };
        $scope.inputDevice.Push(newElem);
        $scope.selectedDevice = newElem.value;
    };


});

Et voici le code HTML:

<div ng-app="testApp">
    <div ng-controller="Ctrl">
        <p>
            <input type="text" ng-model="newInput" />
            <br />
            <button ng-click="addType()">Add Type</button>
        </p>
        <select ng-model="selectedDevice">
            <option></option>
            <option ng-repeat="i in inputDevice" value="{{ i.value }}">{{ i.label }} - {{ i.value }}</option>
        </select>
        {{ selectedDevice }}</div>
</div>
61
Jhorra

C'est exactement pourquoi vous ne devriez pas utiliser ngRepeat pour rendre les options de sélection. Vous devriez utiliser ngOptions à la place:

<select ng-model="selectedDevice" 
        ng-options="i.value as (i.label + '-' + i.value) for i in inputDevice">
    <option></option>
</select>

En général, évitez d’utiliser ngRepeat pour les options de rendu du rendu. Il y a au moins deux bonnes raisons. ngRepeat crée une portée enfant distincte par itération, ce qui n'est pas nécessaire dans le cas d'une balise d'option. Un autre inconvénient important est que, avec ngRepeat, vous ne pouvez lier que sélectionner des primitives telles que des chaînes, mais vous ne pourrez pas écrire d'objet sur ngModel avec celle-ci.

Voici une démo ci-dessous.

angular.module('demo', []).controller('DemoController', function($scope) {

    $scope.newInput = '';
    $scope.inputDevice = [
        {value: '1', label: 'input1'}, 
        {value: '2', label: 'input2'}
    ];
    
    $scope.selectedDevice = '';
    $scope.addType = function() {
        var newElem = {
            label: $scope.newInput,
            value: Number($scope.inputDevice[$scope.inputDevice.length - 1].value) + 1
        };
        $scope.inputDevice.Push(newElem);
        $scope.selectedDevice = newElem.value;
        $scope.newInput = '';
    };

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js"></script>
<div ng-app="demo" ng-controller="DemoController">
    <form ng-submit="addType()">
        <input type="text" ng-model="newInput" />
        <button type="submit">Add Type</button>
    </form>
    <select ng-model="selectedDevice" ng-options="i.value as (i.label + ' - ' + i.value) for i in inputDevice">
        <option>Select</option>
    </select>
    {{ selectedDevice }}
</div>
92
dfsq

Le problème est que, puisque vous n'utilisez pas ng-options le navigateur n’a pas terminé le rendu au moment où vous définissez le nouveau selectedDevice. Si vous êtes prêt à utiliser ng-options vous pouvez utiliser cette solution de contournement. Utilisation $timeout pour envelopper votre $scope.selectedDevice = newElem.value; pour s’assurer que le navigateur a fini de restituer les modifications avec ng-repeat.

J'ai également ajouté du code pour incrémenter la valeur suivante lors d'ajouts successifs, car le codage en dur de '3' signifiait que la troisième option serait continuellement sélectionnée même lorsque d'autres éléments étaient ajoutés.

var testApp = angular.module('testApp', ['ngRoute']);

testApp.controller('Ctrl', function($scope, $timeout) {

  $scope.newInput = '';
  $scope.inputDevice = [{
    value: '1',
    label: 'input1'
  }, {
    value: '2',
    label: 'input2'
  }];
  $scope.selectedDevice = '';

  $scope.addType = function() {
    var last = Number($scope.inputDevice[$scope.inputDevice.length - 1].value) + 1;
    var newElem = {
      label: $scope.newInput,
      value: last.toString()
    };
    $scope.inputDevice.Push(newElem);
    $timeout(function() {
      $scope.selectedDevice = newElem.value;
    }, 0);
  };

});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular-route.js"></script>

<div ng-app="testApp">
  <div ng-controller="Ctrl">
    <p>
      <input type="text" ng-model="newInput" />
      <br />
      <button ng-click="addType()">Add Type</button>
    </p>
    <select ng-model="selectedDevice">
      <option></option>
      <option ng-repeat="i in inputDevice" value="{{ i.value }}" ng-selelected="{{ selectedDevice == i.value }}">{{ i.label }} - {{ i.value }}</option>
    </select>
    {{ selectedDevice }}
  </div>
</div>
8
JME

J'ai eu un problème similaire et la raison était que ma clé était un nombre, mais lorsque j'essayais de définir une autre valeur, j'envoyais une chaîne. La solution de contournement dans ce cas consiste à forcer à définir la valeur du modèle sur le même type que la clé.

par exemple:

<select ng-model="model" ng-options="option.{{ key }} as option.{{ label }} for option in options">
    <option value="">{{ emptyLabel }}</option>
</select>
if (scope.options.length > 0) {
    scope.keyType = typeof(scope.options[0][scope.key]);
}

...

if (scope.keyType == 'number') {
    scope.model = parseInt(newVal, 10);
} else {
    scope.model = newVal;
} 
4
Romain

J'ai eu le même problème de select not update quand ng-model est mis à jour. J'étais en train de récupérer la valeur de ng-model à partir d'une fonction qui extrait l'objet du tableau en se basant sur une paire clé/valeur.

Ce faisant, l’objet retourné avait la propriété hashkey $$hashKey: "object:115"

Le problème est survenu lorsque j'ai créé une copie de l'objet à l'aide de angular.copy, qui a supprimé cette propriété 'hashkey' et n'a donc pas été sélectionnée.

Après avoir réorganisé le code pour obtenir la valeur de ng-model après angular.copy, le problème était résolu.

ConstructorReviewers: function (oItem) {
      this.PERSON_ID = oItem.PERSON_ID;
      this.CHAIR_PERSON = oItem.CHAIR_PERSON;

      /* // Commented this part and added it to EditItem function      
      this.oDepartment = CommonFactory.FindItemInArray(vm.oCommittee.arrDepartments, 'NAME', this.DEPARTMENT, 'item');
      */    
      this.EditItem = function () {
           vm.EditItemOriginal = this;
           angular.copy(this, vm.EditItem); // After this update the ng-model into vm.EditItem.oTitle object
           vm.EditItem.oTitle = CommonFactory.FindItemInArray(vm.oCommittee.arrTitles, 'TITLE', vm.EditItem.TITLE, 'item');
           vm.Popup.ShowPopup(true, 'new_edit', Constants.Mentoring.Popup.Edit);
      }
}
1
Mahesh

J'ai eu le même problème. Ce qui a résolu le problème pour moi est de convertir le nombre en chaîne. Exemple:

$scope.selectedDevice = "" + newElem.value; 
1
Malek Hijazi