web-dev-qa-db-fra.com

Impossible de définir la valeur sélectionnée de ng-options

J'essaie de remplir une liste d'options de sélection déroulante et de définir une valeur sélectionnée par défaut à l'aide de ng-model et de ng-options.

J'ai le code suivant à mon avis:

<select ng-model="thisTour.site" ng-options="site.name for site in siteList"></select>

Et dans mon contrôleur:

    $scope.siteList = [
        { id: 1, name: 'cycling'},
        { id: 2, name: 'walking'},
        { id: 3, name: 'holidays'}
    ]

    $scope.thisTour.site = { id: 2, name: 'walking'};

La liste est remplie avec les 3 options correctes de l'objet siteList, mais il ne sélectionne pas en marchant par défaut comme prévu Pourquoi pas?

Maintenant, quand je change ceci:

$scope.thisTour.site = { id: 2, name: 'walking'};

Pour ça:

$scope.thisTour.site = $scope.siteList[1];

Maintenant ça marche. Pourquoi? N'est-ce pas la même chose?

14
Inigo

En effet, angular cherche l'égalité des objets pour le lier à votre syntaxe et, dans votre cas, $scope.siteList[1] n'est pas égal à { id: 2, name: 'walking'}; (2 objets ne sont égaux que s'ils pointent vers la même référence). Vous pouvez contourner ce problème de plusieurs façons. Une méthode simple consiste à utiliser la syntaxe track by avec ng-options pour spécifier le suivi par id, ce qui permettra aux options de ng-option d'être suivies par la propriété spécifiée de l'objet lié plutôt que par la référence de l'objet. lui-même.

<select ng-model="thisTour.site" 
    ng-options="site.name for site in siteList track by site.id"></select>

Vous pouvez également utiliser la syntaxe pour définir de manière minimale le modèle-ng de manière à ne spécifier que l'ID à l'aide de select en tant que partie dans la syntaxe: -

Exemple:-

ng-options="site.id as site.name for site in siteList"

et le modèle serait juste: -

 $scope.thisTour.site = 2;

angular.module('app', []).controller('ctrl', function($scope){
  $scope.thisTour = {};
 $scope.siteList = [
        { id: 1, name: 'cycling'},
        { id: 2, name: 'walking'},
        { id: 3, name: 'holidays'}
    ]

    $scope.thisTour.site = { id: 2, name: 'walking'};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
  <select ng-model="thisTour.site" ng-options="site.name for site in siteList track by site.id"></select>
  {{thisTour.site}}
  </div>

De documentation

trackexpr: - Utilisé pour travailler avec un tableau d'objets. Le résultat de cette expression sera utilisé pour identifier les objets du tableau. Trackexpr fera très probablement référence à la variable de valeur (par exemple, valeur.nom_propriété). Avec cela, la sélection est conservée même lorsque les options sont recréées (par exemple, rechargées à partir du serveur).

À noter également:

N'utilisez pas select as et track by dans la même expression. Ils ne sont pas conçus pour fonctionner ensemble.

44
PSL

Ce n'est pas la même chose parce que les objets en javascript sont passés par référence .

Si vous prenez le premier exemple:

$scope.siteList = [
    { id: 1, name: 'cycling'},
    { id: 2, name: 'walking'},
    { id: 3, name: 'holidays'}
]

$scope.thisTour.site = { id: 2, name: 'walking'};

Ensuite, vous faites ceci:

$scope.thisTour.site.id = 3;
console.log($scope.siteList[1].id) // 2

En d'autres termes, alors que vos deux objets ont la même valeur dans value , ils ne sont pas le même objet. La directive ngOptions voit cela, donc définirait thisTour.site sur une valeur vide car ce n'est pas l'une des options autorisées.

Google "passe par référence en javascript" pour en savoir plus.

3
Ed Hinchliffe

Puisque vous utilisez l'intégralité de l'objet dans votre sélection, lorsque Angular effectuera la comparaison, il verra si les objets sont identiques afin de définir votre sélection. Je pense qu'il existe un moyen de modifier la fonctionnalité de la façon dont Angular compare ses comparaisons, mais je me contente de parcourir la sélection et de faire mes propres comparaisons similaires à celles ci-dessous:

$scope.siteList = [
        { id: 1, name: 'cycling'},
        { id: 2, name: 'walking'},
        { id: 3, name: 'holidays'}
    ]
angular.forEach($scope.siteList, function(site, index) {
    if (site.id == 2) {
        $scope.thisTour.site = site;
    }
});

Cela définira l'objet réel sur votre variable, ce qui permettra de le définir dans la sélection.

1
Matthew Green

Utilisez la directive ng-init .Ce qui est exécuté initialement à un moment donné, nous pouvons affecter une valeur à ngmodel.

<div ng-init="thisTour.site = siteList[position]">
    <select ng-model="thisTour.site" ng-options="site.name for site in  siteList track by site.id"></select>
</div>
0
Arul Ramalingam