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.

Sudhanshu
la source

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.

pkozlowski.opensource
la source
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>
Mark Rajcok
la source
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.

WTK
la source
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

Abraham Jagadeesh
la source
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>
Nabil Boag
la source
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

jusopi
la source
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.

KK
la source
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
@KK stackoverflow.com/questions/48355599/… Pouvez-vous vérifier cela?
Sudarshan Kalebere
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é.

Kanagaraj Vadivel
la source
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>
denkan
la source
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>
James Drinkard
la source
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.

Jitu
la source
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.

kgrondell
la source
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 :)

Marco
la source
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>
MMM
la source
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>
Nayas Subramanian
la source
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.

David Genger
la source
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];
Macfer Ann
la source
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.

lisapanda
la source
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).

Wtower
la source
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>

gajendra kumar
la source
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 KOCH
la source
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'">
Pauly Garcia
la source
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.

Tombe de Kuza
la source
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">

Dipendu Paul
la source
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

ihsanberahim
la source
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);
};
Ashok Kumar
la source