672 votes

Pourquoi AngularJS inclut-il une option vide dans la sélection ?

Je travaille avec AngularJS depuis quelques semaines, et la chose qui me dérange vraiment est que, même après avoir essayé toutes les permutations ou la configuration définie dans la spécification à l'adresse http://docs.angularjs.org/api/ng.directive:select J'obtiens toujours une option vide comme premier enfant de l'élément select.

Voici la Jade :

select.span9(ng-model='form.type', required, ng-options='option.value as option.name for option in typeOptions');

Voici le contrôleur :

$scope.typeOptions = [
    { name: 'Feature', value: 'feature' },
    { name: 'Bug', value: 'bug' },
    { name: 'Enhancement', value: 'enhancement' }
];

Enfin, voici le HTML qui est généré :

<select ng-model="form.type" required="required" ng-options="option.value as option.name for option in typeOptions" class="span9 ng-pristine ng-invalid ng-invalid-required">
    <option value="?" selected="selected"></option>
    <option value="0">Feature</option>
    <option value="1">Bug</option>
    <option value="2">Enhancement</option>
</select>

Que dois-je faire pour m'en débarrasser ?

P.S. : Les choses fonctionnent aussi sans cela, mais cela semble bizarre si vous utilisez select2 sans sélection multiple.

656voto

pkozlowski.opensource Points 52557

Le vide option est généré lorsqu'une valeur référencée par ng-model n'existe pas dans un ensemble d'options passées à l'option ng-options . Cela se produit pour éviter la sélection accidentelle d'un modèle : AngularJS peut voir que le modèle initial est soit indéfini soit ne fait pas partie de l'ensemble des options et ne veut pas décider de la valeur du modèle par lui-même.

Si vous voulez vous débarrasser de l'option vide, sélectionnez simplement une valeur initiale dans votre contrôleur, quelque chose comme :

$scope.form.type = $scope.typeOptions[0].value;

Voici le jsFiddle : http://jsfiddle.net/MTfRD/3/

En bref : l'option vide signifie qu'aucun modèle valide n'est sélectionné (par valide, j'entends : parmi l'ensemble des options). Vous devez sélectionner une valeur de modèle valide pour vous débarrasser de cette option vide.

8 votes

J'ai essayé avec les deux $scope.form.type = '' ; et $scope.form.type = $scope.typeOptions[0], cependant je vois toujours ceci - <option value=" ?" selected="selected"></option>

2 votes

Désolé, la ligne avec HTML était si longue que je n'ai pas remarqué que vous liez des noms, et non les objets complets. Veuillez essayer avec $scope.typeOptions[0].value, si cela ne fonctionne toujours pas, je vous enverrai un jsFiddle avec un exemple.

5 votes

Parfois, il n'est vraiment pas utile d'avoir ces données dans le JS. Si c'est le serveur qui a décidé de ce qui se trouvait dans cette sélection, pourquoi le JS devrait-il le reproduire ?

241voto

Mark Rajcok Points 85912

Si vous voulez une valeur initiale, consultez la réponse de @pkozlowski.opensource, qui, pour votre information, peut également être implémentée dans la vue (plutôt que dans le contrôleur) en utilisant ng-init :

<select ng-model="form.type" required="required" ng-init="form.type='bug'"
  ng-options="option.value as option.name for option in typeOptions" >
</select>

Si vous ne voulez pas de valeur initiale, "un seul élément codé en dur, dont la valeur est définie comme une chaîne vide, peut être imbriqué dans l'élément. Cet élément représentera alors l'option nulle ou "non sélectionnée"" :

<select ng-model="form.type" required="required"
  ng-options="option.value as option.name for option in typeOptions" >
    <option style="display:none" value="">select a type</option>
</select>

4 votes

@hugo, violon d'Ingres : jsfiddle.net/4qKyx/1 Notez que "sélectionner un type" est affiché, mais qu'aucune valeur ne lui est associée. Et une fois que vous aurez sélectionné autre chose, vous ne le verrez plus. (Test sur Chrome.)

0 votes

Cette solution fonctionne mieux pour moi. La solution de @pkozlowski.opensource fonctionne aussi, cependant, dans mon application, elle fait que les produits n'apparaissent pas dans le panier après. Merci !

1 votes

@MarkRajcok - excellente suggestion ! J'ai rencontré un autre problème en utilisant votre exemple avec la directive de transclusion. Pourriez-vous y jeter un coup d'œil ? plnkr.co/edit/efaZdEQlNfoDihk1R1zc?p=preview

123voto

WTK Points 7883

Angular < 1.4

Pour tous ceux qui considèrent que "null" est une valeur valide pour l'une des options (imaginez que "null" est une valeur de l'un des éléments de la liste des options), il n'y a pas de problème. typeOptions dans l'exemple ci-dessous), j'ai trouvé que la façon la plus simple de s'assurer que l'option ajoutée automatiquement est cachée est d'utiliser ng-if.

<select ng-options="option.value as option.name for option in typeOptions">
    <option value="" ng-if="false"></option>
</select>

Pourquoi ng-if et non pas ng-hide ? Parce que vous voulez que les sélecteurs css qui ciblent la première option dans la sélection ci-dessus ciblent la "vraie" option, pas celle qui est cachée. Cela devient utile lorsque vous utilisez Protractor pour les tests e2e et que (pour une raison quelconque) vous utilisez by.css() pour cibler les options de sélection.

Angular >= 1.4

En raison du remaniement des directives select et options, l'utilisation de la directive ng-if n'est plus une option viable, vous devez donc vous tourner vers ng-show="false" pour le faire fonctionner à nouveau.

5 votes

Ce devrait être la réponse acceptée, car c'est le comportement visuel correct pour la sélection. Vous mettez size="5" aux attributs de sélection et vous pouvez voir qu'il n'y a rien de sélectionné ! Comme dans une fenêtre par défaut <select> -Element ! Je n'arrive pas à comprendre pourquoi angular fait une telle chose pour les selects sans multiple attribut...

1 votes

Oui, je suis d'accord, cela devrait être la réponse acceptée. C'est la "méthode angulaire". ng-if supprime en fait l'élément options du domaine (lorsqu'il est faux), de sorte que cette solution fonctionne également sur tous les navigateurs sans codage "bricolé" (contrairement à ng-hide ou ng-show).

2 votes

@Sander_P par définition cette solution est du codage "hacky" à mon avis (mettre quelque chose dans le dom pour inciter angular à le retirer), mais vous avez raison c'est toujours la "meilleure" solution. La solution "encore meilleure" serait d'autoriser un putain de select qui n'a aucune valeur ! Et puis quoi encore ? Ce n'est pas comme si c'était un scénario limite.

36voto

Abraham Jagadeesh Points 156

Peut-être utile pour quelqu'un :

Si vous voulez utiliser des options simples au lieu de ng-options, vous pouvez faire comme ci-dessous :

<select ng-model="sortorder" ng-init="sortorder='publish_date'">
  <option value="publish_date">Ascending</option>
  <option value="-publish_date">Descending</option>
</select>

Définissez le modèle en ligne. Utilisez ng-init pour vous débarrasser de l'option vide.

0 votes

Je n'ai pas été en mesure de trouver un exemple clair de mise en place de ng-options avec des OBJETS plutôt qu'avec des tableaux JSON et lorsque j'essaie de "traduire" entre les deux, non seulement le résultat n'est pas bon, mais il échoue "silencieusement", de sorte que je n'ai aucune idée de ce que je fais de mal. J'ai finalement opté pour un simple ng-repeat dans une balise d'option. Je sais que ce n'est pas la meilleure pratique, mais au moins ça marche. Si quelqu'un peut m'indiquer un exemple fonctionnel simple, facilement interchangeable dans les détails et adapté à angular-n00b, utilisant ng-options avec des objets de données (PAS JSON), je serais ravi. Je serais doublement ravi s'il utilise également ng-init.

0 votes

J'utilise des options simples, mais dans le contrôleur, je ne semble pas obtenir la valeur de la liste déroulante sélectionnée. Ex : J'ai essayé alert($scope.sortorder.value) ; et alert($scope.sortorder) ; les deux donnent undefined. Comment obtenir la valeur sélectionnée ici ?

0 votes

Merci beaucoup pour cela. J'étais sur le point d'écrire un objet complètement inutile dans le contrôleur dont je n'avais pas besoin, j'avais juste besoin d'un simple select Merci encore une fois.

14voto

Oui, le ng-model créera une valeur d'option vide, lorsque la propriété du ng-model est indéfinie. Nous pouvons éviter cela si nous assignons un objet au ng-model.

Exemple

codage angulaire

$scope.collections = [
    { name: 'Feature', value: 'feature' }, 
    { name: 'Bug', value: 'bug' }, 
    { name: 'Enhancement', value: 'enhancement'}
];

$scope.selectedOption = $scope.collections[0];

<select class='form-control' data-ng-model='selectedOption' data-ng-options='item as item.name for item in collections'></select>

Note importante :

Assignez l'objet du tableau comme $scope.collections[0] ou $scope.collections[1] au ng-model, n'utilisez pas les propriétés de l'objet. Si vous obtenez la valeur de l'option sélectionnée du serveur, en utilisant la fonction de rappel, assignez l'objet au ng-model.

NOTE du document Angular

Remarque : ngModel compare par référence, et non par valeur. Ceci est important lorsque l'on lie un tableau d'objets. voir un exemple http://jsfiddle.net/qWzTb/

J'ai essayé de nombreuses fois et j'ai fini par le trouver.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X