Pourquoi AngularJS inclut une option vide dans select?


652

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

Voici le 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?

PS: Les choses fonctionnent également sans cela, mais cela semble étrange si vous utilisez select2 sans sélection multiple.

Réponses:


646

Le vide optionest généré lorsqu'une valeur référencée par ng-modeln'existe pas dans un ensemble d'options passées à ng-options. Cela empêche la sélection accidentelle de modèle: AngularJS peut voir que le modèle initial n'est pas défini ou ne fait pas partie de l'ensemble d'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 je veux dire: parmi l'ensemble des options). Vous devez sélectionner une valeur de modèle valide pour vous débarrasser de cette option vide.


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

5
Parfois, cela n'a vraiment aucun sens d'avoir ces données dans le JS. Si c'est le serveur qui a pris la décision sur ce qu'il y avait dans cette sélection, pourquoi le JS devrait-il le dupliquer?
heneryville

11
Cela ne fonctionne malheureusement pas si vous utilisez un tableau et nullest l'une de vos valeurs.
vpiTriumph

6
Est-il possible d'ajouter un texte à l'intérieur du vide <option>afin que tat angulaire génère quelque chose comme<option value="?">Select an option</option>
RPDeshaies

3
@ Tareck117 wirte <option value="">Select an option</option>c'est la valeur null de la liste d'options. Pas besoin de caractère?.
Sebastian

235

Si vous voulez une valeur initiale, voir la réponse de @ pkozlowski.opensource, que FYI peut également être implémenté 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, avec la valeur définie sur une chaîne vide, peut être imbriqué dans l'élément. Cet élément représentera alors une 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
@hugo, fiddle de travail: jsfiddle.net/4qKyx/1 Notez que "sélectionnez un type" est affiché, mais il n'y a aucune valeur qui lui est associée. Et une fois que vous avez sélectionné autre chose, vous ne le verrez plus. (Test sur Chrome.)
Mark Rajcok

1
@MarkRajcok - excellente suggestion! j'ai trébuché sur un autre problème en utilisant votre exemple avec transcluding directive. Pourriez-vous s'il vous plaît jeter un oeil? plnkr.co/edit/efaZdEQlNfoDihk1R1zc?p=preview
Jan-Terje Sørensen

2
Le problème est que vous pouvez toujours sélectionner avec le clavier, voir la solution stackoverflow.com/a/8442831/57344
HaveAGuess

2
Cela peut fonctionner pour l'instant, mais la documentation angulaire recommande spécifiquement de ne pas utiliser ng-init pour autre chose que ng-repeat - voir docs.angularjs.org/api/ng/directive/ngInit
Ed Norris

3
Ne fonctionne pas dans IE10, le "sélectionner un type" est toujours visible et sélectionnable.
Robin

121

Angulaire <1,4

Pour tous ceux qui traitent "null" comme une valeur valide pour l'une des options (alors imaginez que "null" est une valeur de l'un des éléments de typeOptions dans l'exemple ci-dessous), j'ai trouvé le moyen le plus simple de vous assurer que automatiquement ajouté L'option 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 pas ng-hide? Parce que vous voulez que les sélecteurs css qui ciblent la première option à l'intérieur ci-dessus sélectionnent pour cibler l'option "réelle", pas celle qui est cachée. Il devient utile lorsque vous utilisez le rapporteur pour les tests e2e et (pour une raison quelconque) vous utilisez by.css () pour cibler les options de sélection.

Angulaire> = 1,4

En raison de la refactorisation des directives select et options, l'utilisation ng-ifn'est plus une option viable, vous devez donc vous tourner ng-show="false"pour la faire fonctionner à nouveau.


5
Doit être la réponse acceptée, car il s'agit du comportement visuel correct pour la sélection. Vous mettez size="5"les attributs selects et vous pouvez voir qu'il n'y a rien de sélectionné! Comme dans un <select>-Element par défaut ! Je ne comprends pas pourquoi angular fait une telle chose pour les sélections sans multipleattribut ...
Sebastian

1
Oui, je suis d'accord, cela devrait être la réponse acceptée. C'est la «voie angulaire». ng-if supprime en fait l'élément options du dom (si false), cette solution fonctionne également sur tous les navigateurs sans codage «hacky» (contrairement à ng-hide ou ng-show).
Sander_P

2
@Sander_P par définition, cette solution est un codage "hacky" à mon avis (mettre quelque chose dans le dom pour tromper angulairement en le supprimant), mais vous avez raison, c'est toujours la "meilleure" solution. La solution "encore meilleure" serait de permettre une sélection friggin qui n'a aucune valeur! Que diable? Ce n'est pas comme si c'était un scénario de pointe.
dudewad

@dudewad: les choses pourraient mieux fonctionner avec Angular 1.4. Du blog AngularJS pour 1.4.0: "ngOptions a été complètement refactorisé pour permettre la correction d'un certain nombre de bugs ennuyeux",
Sander_P

1
Haha "bugs ennuyeux". D'accord. Eh bien, je suis toujours un peu skiddish en ce qui concerne la mise à niveau 3 jours avant la livraison, donc je vais continuer avec votre solution pour l'instant, qui semble fonctionner à merveille. Noté pour l'avenir, cependant :) Merci!
dudewad

36

Peut-être utile pour quelqu'un:

Si vous souhaitez 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 se débarrasser de l'option vide


Je n'ai pas été en mesure de trouver un exemple clair de configuration de ng-options avec OBJECTS plutôt qu'avec des tableaux JSON et lorsque j'essaie de "traduire" entre les deux, non seulement cela ne se passe pas bien mais il échoue "silencieusement" donc Je n'ai aucune idée de ce que je fais mal. J'ai finalement opté pour plain 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 me pointer vers un exemple de travail simple et facilement échangeable sur les détails, angulaire-n00b-friendly utilisant ng-options avec des objets de données (PAS JSON), je serais ravi. Double exalté s'il utilise également ng-init.
code-sushi

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

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'une simple sélection. Merci encore.
Muhammad bin Yusrat

22

Quelque chose de similaire m'arrivait aussi et était causé par une mise à niveau vers angular 1.5. ng-initsemble être analysé pour le type dans les nouvelles versions d'Angular. Dans les versions plus anciennes, Angular mapperait ng-init="myModelName=600"sur une option avec une valeur "600", <option value="600">First</option>mais dans Angular 1.5, il ne trouverait pas cela car il semble s'attendre à trouver une option avec une valeur 600 ie <option value=600>First</option>. Angular insèrerait alors un premier élément aléatoire:

<option value="? number:600 ?"></option>

Angulaire <1.2.x

<select ng-model="myModelName" ng-init="myModelName=600">
  <option value="600">First</option>
  <option value="700">Second</option>
</select>

Angulaire> 1,2

<select ng-model="myModelName" ng-init="myModelName='600'">
  <option value="600">First</option>
  <option value="700">Second</option>
</select>

1
Merci! Dans mon cas, je ne peux pas utiliser ng-init (pas de valeur par défaut), j'ai donc converti mon modèle en chaîne et cela a fonctionné!
Rodrigo Graça

Très utile pour mon problème de production d'applications. Merci @Nabil Boag
Venki

3
Cela fonctionne, bien sûr, mais la meilleure option est d'utiliser ng-value="600"à la optionplace de value. Il va l'analyser en un nombre et vous n'avez pas à convertir vos valeurs comme vous le faites maintenant :)
Max

@Max J'ai essayé beaucoup de réponses de grande valeur, mais aucune n'a fonctionné jusqu'à ce que je trouve la vôtre. Je vous remercie.
Andrew

21

Parmi la multitude de réponses ici, je me suis dit que je republierais la solution qui fonctionnait pour moi et remplissait toutes les conditions suivantes:

  • fourni un espace réservé / invite lorsque le modèle ng est faux (par exemple "--select region--" w.value="" )
  • lorsque la valeur du modèle ng est fausse et que l'utilisateur ouvre la liste déroulante des options, l'espace réservé est sélectionné (les autres solutions mentionnées ici font apparaître la première option sélectionnée, ce qui peut être trompeur)
  • permettre à l'utilisateur de désélectionner une valeur valide, en sélectionnant essentiellement à nouveau la valeur falsifiée / par défaut

entrez la description de l'image ici

code

<select name="market_vertical" ng-model="vc.viewData.market_vertical"
    ng-options="opt as (opt | capitalizeFirst) for opt in vc.adminData.regions">

    <option ng-selected="true" value="">select a market vertical</option>
</select>

src

questions et réponses originales - https://stackoverflow.com/a/32880941/1121919


Voulez-vous dire si la valeur par défaut est <option ng-selected="true" value="null">?
jusopi

Je veux dire que si la valeur du modèle ng est définie comme nulle, la création angulaire et l'option vide sur la sélection
Flezcano

16

Une solution rapide:

select option:empty { display:none }

J'espère que cela aide quelqu'un. Idéalement, la réponse choisie devrait être l'approche, mais si ce n'est pas possible, elle devrait fonctionner comme un patch.


2
D'après mes tests, cela ne fonctionnera que dans Chrome (nouveau Chrome, en plus de cela) et Firefox. IE et Safari se cassent. Je ne connais pas l'opéra et les autres navigateurs de pointe. Quoi qu'il en soit, ce n'est malheureusement pas une bonne solution.
dudewad

où devrions-nous placer cela en html avant la fermeture de <select> ou bien dans le js
H Varma

1
@HVarma C'est une règle CSS. Placez-le dans la feuille de style ou dans la balise <style>
KK


14

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

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 un objet du tableau comme $ scope.collections [0] ou $ scope.collections [1] à ng-model, n'utilisez pas les propriétés d'objet. si vous obtenez la valeur de l'option de sélection du serveur, en utilisant la fonction de rappel, affectez l'objet au modèle ng

NOTE du document angulaire

Remarque: ngModel compare par référence, pas par valeur. Ceci est important lors de la liaison à un tableau d'objets. voir un exemple http://jsfiddle.net/qWzTb/

j'ai essayé beaucoup de fois finalement je l'ai trouvé.


8

Bien que les réponses de @ pkozlowski.opensource et @ Mark soient correctes, je voudrais partager ma version légèrement modifiée où je sélectionne toujours le premier élément de la liste, quelle que soit sa valeur:

<select ng-options="option.value as option.name for option in typeOptions" ng-init="form.type=typeOptions[0].value">
</select>

4

J'utilise Angular 1.4x et j'ai trouvé cet exemple, j'ai donc utilisé ng-init pour définir la valeur initiale dans la sélection:

<select ng-init="foo = foo || items[0]" ng-model="foo" ng-options="item as item.id for item in items"></select>

3


J'ai fait face au même problème. Si vous publiez un formulaire angulaire avec une publication normale, vous serez confronté à ce problème, car angulaire ne vous permet pas de définir des valeurs pour les options de la manière que vous avez utilisée. Si vous obtenez la valeur de "form.type", vous trouverez la bonne valeur. Vous devez publier l'objet angulaire lui-même et non le formulaire.


3

Une solution simple consiste à définir une option avec une valeur vide ""J'ai trouvé que cela élimine l'option supplémentaire non définie.


5
Ne travaille pas @ 1.4.3, il ajoute juste 2 options vides au formulaire
Denny Mueller

3

Ok, en fait, la réponse est très simple: quand il y a une option non reconnue par Angular, elle en inclut une terne. Ce que vous faites mal, c'est que lorsque vous utilisez ng-options, il lit un objet, par exemple[{ id: 10, name: test }, { id: 11, name: test2 }] right?

Voici ce que doit être la valeur de votre modèle pour l'évaluer comme égale, disons que vous voulez que la valeur sélectionnée soit 10, vous devez définir votre modèle sur une valeur comme { id: 10, name: test } pour sélectionner 10, donc il ne créera PAS cette corbeille.

J'espère que cela aide tout le monde à comprendre, j'ai eu du mal à essayer :)


2

Cette solution fonctionne pour moi:

<select ng-model="mymodel">    
   <option ng-value="''" style="display:none;" selected>Country</option>
   <option value="US">USA</option>
</select>

Le downvote pourrait être dû au fait que l'application de CSS aux éléments d'option ne fonctionne pas sur tous les navigateurs.
Kafoso

Je viens de le tester sur Chrome, FireFox, Safari et Edge - tout fonctionne.
MMM

@MMM "tous les navigateurs" inclut IE. Beaucoup d'utilisateurs sont toujours bloqués avec IE 10 et 11, et c'est probablement pourquoi le downvote s'est produit. Chrome, fF, Saf et Edge ne sont pas "tous les navigateurs".
PKD

1

Cela a fonctionné pour moi

<select ng-init="basicProfile.casteId" ng-model="basicProfile.casteId" class="form-control">
     <option value="0">Select Caste....</option>
     <option data-ng-repeat="option in formCastes" value="{{option.id}}">{{option.casteName}}</option>
 </select>

Ajoute simplement l'option dans la liste et laisse malheureusement l'espace vide.
AMontpetit

1

Cela fonctionne parfaitement bien

<select ng-model="contact.Title" ng-options="co for co in['Mr.','Ms.','Mrs.','Dr.','Prof.']">
    <option style="display:none" value=""></option>
</select>

la façon dont cela fonctionne est que cela donne la première option à afficher avant de sélectionner quelque chose et le display:nonesupprime du menu déroulant donc si vous voulez, vous pouvez le faire

<select ng-model="contact.Title" ng-options="co for co in['Mr.','Ms.','Mrs.','Dr.','Prof.']">
    <option style="display:none" value="">select an option...</option>
</select>

et cela vous donnera la select and option avant de sélectionner mais une fois sélectionné, il disparaîtra et ne s'affichera pas dans la liste déroulante.


En fait, vous ne répondez pas à la question elle-même, pire que cela, vous cachez simplement l'élément.
Marco

0

Essayez celui-ci dans votre contrôleur, dans le même ordre:

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

J'ai essayé votre méthode mais malheureusement je n'ai pas pu la faire fonctionner. Pouvez-vous jeter un œil à ce violon. jsfiddle.net/5PdaX
Sinha

0

Voici le correctif:

pour un échantillon de données comme:

financeRef.pageCount = [{listCount:10,listName:modelStrings.COMMON_TEN_PAGE},    
{listCount:25,listName:modelStrings.COMMON_TWENTYFIVE_PAGE},
{listCount:50,listName:modelStrings.COMMON_FIFTY_PAGE}];

L'option de sélection doit être comme ceci: -

<select ng-model="financeRef.financeLimit" ng-change="financeRef.updateRecords(1)" 
class="perPageCount" ng-show="financeRef.showTable" ng-init="financeRef.financeLimit=10"
ng-options="value.listCount as value.listName for  value in financeRef.pageCount"
></select>

Le point étant lorsque nous écrivons en value.listCounttant que value.listName, il remplit automatiquement le texte value.listNamemais la valeur de l'option sélectionnée estvalue.listCount bien que les valeurs mes soient normales 0,1,2 .. et ainsi de suite !!!

Dans mon cas, le financeRef.financeLimitsaisit en fait le value.listCountet je peux faire ma manipulation dans le contrôleur dynamiquement.


0

Je voudrais ajouter que si la valeur initiale provient d'une liaison d'un élément parent ou d'un composant 1.5, assurez-vous que le type approprié est transmis. Si vous utilisez@ dans la liaison, la variable passée sera une chaîne et si les options sont par exemple. entiers, puis l'option vide apparaîtra.

Soit analyser correctement la valeur dans init, soit lier avec <et non @(moins recommandé pour les performances sauf si nécessaire).


0

Solution simple

<select ng-model='form.type' required><options>
<option ng-repeat="tp in typeOptions" ng-selected="    
{{form.type==tp.value?true:false}}" value="{{tp.value}}">{{tp.name}}</option>


0

Une solution de mouture avec jQuery lorsque vous n'avez pas le contrôle des options

html:

<select id="selector" ng-select="selector" data-ng-init=init() >
...
</select>

js:

$scope.init = function () {
    jQuery('#selector option:first').remove();
    $scope.selector=jQuery('#selector option:first').val();
}

Pascal, quelqu'un vous a déçu parce que c'est une solution jQuery, pas AngularJs
Mawg dit réintégrer Monica

La question est posée de creuser le plus d'Angular ...: - /
Sahu V Kumar

0

Si vous utilisez ng-init votre modèle pour résoudre ce problème:

<select ng-model="foo" ng-app ng-init="foo='2'">

0

j'ai eu le même problème, j'ai (supprimé "ng-model") changé ceci:

<select ng-model="mapayear" id="mapayear" name="mapayear" style="  display:inline-block !important;  max-width: 20%;" class="form-control">
  <option id="removable" hidden> Selecione u </option>
    <option selected ng-repeat="x in anos" value="{{ x.ano }}">{{ x.ano }}
</option>
</select>

pour ça:

<select id="mapayear" name="mapayear" style="  display:inline-block !important;  max-width: 20%;" class="form-control">
  <option id="removable" hidden> Selecione u </option>
    <option selected ng-repeat="x in anos" value="{{ x.ano }}">{{ x.ano }}
</option>
</select>

maintenant ça marche, mais dans mon cas, c'est parce que j'ai supprimé cette portée de ng.controller, vérifiez si vous n'avez pas fait la même chose.



0

La seule chose qui a fonctionné pour moi est d'utiliser track bydans ng-options, comme ceci:

 <select class="dropdown" ng-model="selectedUserTable" ng-options="option.Id as option.Name for option in userTables track by option.Id">


si j'utilise ceci, ng-optionobtenez la dernière valeur du tableau dont je veux définir la valeur optionde select. Il n'a pas résolu :(
rufatZZ

0

Reportez-vous à l'exemple de la documentation angularjs pour résoudre ces problèmes.

  1. Accédez à ce lien de documentation ici
  2. Rechercher ' Sélection de liaison à une valeur non chaîne via l'analyse / formatage ngModel '
  3. Là, vous pouvez y voir, la directive appelée ' convertToNumber ' résout le problème.

Ça marche pour moi. Peut également voir comment cela fonctionne ici


0

Nous pouvons utiliser CSS pour masquer la première option, mais cela ne fonctionnera pas dans IE 10, 11. La meilleure façon est de supprimer l'élément à l'aide de Jquery. Cette solution fonctionne pour les principaux navigateurs testés dans Chrome et IE10, 11

Aussi, si vous utilisez angulaire, parfois en utilisant setTimeout fonctionne

$scope.RemoveFirstOptionElement = function (element) {
    setTimeout(function () {
        $(element.children()[0]).remove();
    }, 0);
};
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.