Perché AngularJS include un'opzione vuota in select?


652

Ho lavorato con AngularJS nelle ultime settimane e l'unica cosa che mi dà davvero fastidio è che anche dopo aver provato tutte le permutazioni o la configurazione definita nelle specifiche su http://docs.angularjs.org/api/ng .directive: select , ho ancora un'opzione vuota come primo figlio dell'elemento select.

Ecco la giada:

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

Qui il controller:

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

Infine, ecco l'HTML che viene generato:

<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>

Cosa devo fare per liberarmene?

PS: Le cose funzionano anche senza questo, ma sembra strano se usi select2 senza selezione multipla.

Risposte:


646

Il vuoto optionviene generato quando un valore a cui ng-modelfa riferimento non esiste in una serie di opzioni passate ang-options . Ciò accade per impedire la selezione accidentale del modello: AngularJS può vedere che il modello iniziale non è definito o non è nel gruppo di opzioni e non vuole decidere da solo il valore del modello.

Se vuoi sbarazzarti dell'opzione vuota basta selezionare un valore iniziale nel tuo controller, qualcosa del tipo:

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

Ecco il jsFiddle: http://jsfiddle.net/MTfRD/3/

In breve: l'opzione vuota significa che non è stato selezionato alcun modello valido (per valido intendo: dall'insieme di opzioni). È necessario selezionare un valore di modello valido per sbarazzarsi di questa opzione vuota.


7
Ho provato con entrambi $ scope.form.type = ''; e $ scope.form.type = $ scope.typeOptions [0], tuttavia continuo a vedere questo - <opzione valore = "?" selected = "selected"> </option>
Sudhanshu,

5
A volte non ha davvero senso avere questi dati nel JS. Se è il server che ha preso la decisione su cosa c'era in quella selezione, perché JS dovrebbe duplicarlo?
heneryville,

11
Questo purtroppo non funziona se si utilizza un array ed nullè uno dei tuoi valori.
vpiTriumph,

6
È possibile aggiungere un testo all'interno del vuoto in <option>modo che tat angolare abbia generato qualcosa del genere<option value="?">Select an option</option>
RPDeshaies

3
@ Tareck117 ha appena inserito <option value="">Select an option</option>questo è il valore null dell'elenco opzioni. Non c'è bisogno di? -Character.
Sebastian

235

Se vuoi un valore iniziale, vedi la risposta di @ pkozlowski.opensource, che FYI può anche essere implementata nella vista (piuttosto che nel controller) usando 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>

Se non si desidera un valore iniziale, "un singolo elemento hardcoded, con il valore impostato su una stringa vuota, può essere nidificato nell'elemento. Questo elemento rappresenterà quindi l'opzione null o" non selezionata ":

<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, violino funzionante: jsfiddle.net/4qKyx/1 Nota che viene mostrato "seleziona un tipo", ma non è associato alcun valore. E una volta selezionato qualcos'altro, non lo vedrai più. (Test su Chrome.)
Mark Rajcok

1
@MarkRajcok - eccellente suggerimento! mi sono imbattuto in un altro problema usando il tuo esempio con la direttiva di esclusione. Potresti dare un'occhiata? plnkr.co/edit/efaZdEQlNfoDihk1R1zc?p=preview
Jan-Terje Sørensen,

2
Problemi con questa è che si può ancora scegliere con tastiera, vedere stackoverflow.com/a/8442831/57344 soluzione
HaveAGuess

2
Questo potrebbe funzionare per ora, ma la documentazione angolare raccomanda espressamente di non utilizzare ng-init per nulla oltre a ng-repeat - vedi docs.angularjs.org/api/ng/directive/ngInit
Ed Norris

3
Non funziona in IE10, la "selezione di un tipo" è sempre visibile e selezionabile.
Robin,

121

Angolare <1.4

Per tutti quelli che trattano "null" come valore valido per una delle opzioni (quindi immagina che "null" sia il valore di uno degli elementi in typeOptions nell'esempio seguente), ho trovato il modo più semplice per assicurarmi che aggiunto automaticamente l'opzione è nascosta è usare ng-if.

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

Perché ng-if e non ng-hide? Perché vuoi che i selettori CSS che scelgano come target la prima opzione in alto sopra scelgano come target l'opzione "reale", non quella nascosta. È utile quando si utilizza il goniometro per i test e2e e (per qualsiasi motivo) si utilizza by.css () per scegliere come target le opzioni.

Angolare> = 1.4

A causa del refactoring delle direttive select e options, l'utilizzo ng-ifnon è più un'opzione praticabile, quindi devi rivolgerti ng-show="false"per farlo funzionare di nuovo.


5
Dovrebbe essere la risposta accettata, perché questo è il comportamento visivo corretto per la selezione. Hai messo size="5"agli attributi seleziona i e si può vedere che non c'è niente selezionata! Come in un predefinito <select>-Elemento! Non riesco a capire perché Angular stia facendo una cosa del genere per selects senza multipleattributo ...
Sebastian

1
Sì, sono d'accordo, questa dovrebbe essere la risposta accettata. Questa è la "via angolare". ng-if rimuove effettivamente l'elemento delle opzioni dal dom (quando falso), quindi questa soluzione funziona anche su tutti i browser senza codifica "hacky" (contrariamente a ng-hide o ng-show).
Sander_P

2
@Sander_P per definizione questa soluzione è una codifica "confusa" secondo me (mettere qualcosa nel dom per ingannare l'angolazione nel tirarla fuori), ma hai ragione è ancora la soluzione "migliore". La soluzione "ancora migliore" sarebbe quella di consentire una selezione frigginosa che non ha valore! Che diamine? Non è come questo è uno scenario limite.
Dudewad,

@dudewad: le cose potrebbero funzionare meglio con Angular 1.4. Dal blog AngularJS per 1.4.0: "ngOptions è stato completamente riformulato per consentire la correzione di numerosi bug fastidiosi"
Sander_P,

1
Haha "bug fastidiosi". Va bene. Bene, sono ancora un po 'nervoso quando si tratta di aggiornare 3 giorni prima della consegna, quindi continuerò con la tua soluzione per ora, che sembra funzionare a meraviglia. Notato per il futuro, però :) Grazie!
Dudewad,

36

Forse utile per qualcuno:

Se vuoi usare opzioni semplici invece di ng-options, puoi fare come di seguito:

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

Imposta il modello in linea. Usa ng-init per eliminare l'opzione vuota


Non sono stato in grado di trovare un chiaro esempio di configurazione di ng-options con OBJECTS piuttosto che array JSON e quando provo a "tradurre" tra i due, non solo non viene fuori correttamente ma fallisce "silenziosamente", quindi Non ho idea di cosa stia facendo di sbagliato. Alla fine ho optato per ng-repeat in un tag opzione. So che non è la migliore pratica ma almeno FUNZIONA. Se qualcuno mi può indicare un esempio semplice, facilmente scambiabile sui dettagli, angular-n00b-friendly WORKING usando ng-options con oggetti dati (NON JSON), sarei euforico. Doppio euforico se usa anche ng-init.
code-sushi,

Sto usando opzioni semplici, ma nel controller non sembra ottenere il valore del menu a discesa selezionato. Es: ho provato ad avvisare ($ scope.sortorder.value); e avviso ($ scope.sortorder); entrambi danno indefinito. Come ottenere il valore selezionato qui?
Maverick Riz,

Grazie mille per questo. Stavo per scrivere un oggetto completamente inutile nel controller che non mi serviva, avevo solo bisogno di una semplice selezione .. Grazie ancora.
Muhammad bin Yusrat,

22

Qualcosa di simile stava accadendo anche a me ed è stato causato da un aggiornamento alla versione angolare 1.5. ng-initsembra essere analizzato per il tipo nelle versioni più recenti di Angular. Nella versione precedente, Angular ng-init="myModelName=600"verrebbe mappato su un'opzione con valore "600", ad esempio, <option value="600">First</option>ma in Angular 1.5 non lo troverà in quanto sembra aspettarsi di trovare un'opzione con valore 600 ie <option value=600>First</option>. Angular inserisce quindi un primo elemento casuale:

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

Angolare <1.2.x

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

Angolare> 1.2

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

1
Grazie! Nel mio caso non posso usare ng-init (nessun valore predefinito), quindi ho lanciato il mio modello su una stringa e ha funzionato!
Rodrigo Graça,

Molto utile per il mio problema di produzione dell'applicazione. Grazie @Nabil Boag
Venki

3
Funziona, certo, ma le opzioni migliori sono da usare ng-value="600" al optionposto di value. Lo analizzerà in un numero e non dovrai convertire i tuoi valori come fai ora :)
Max

@Max Ho provato molte risposte di alto valore, ma nessuna ha funzionato fino a quando non ho trovato le tue. Grazie.
Andrew,

21

Tra la moltitudine di risposte qui, ho pensato di ripubblicare la soluzione che ha funzionato per me e ho soddisfatto tutte le seguenti condizioni:

  • fornito un segnaposto / prompt quando il modello ng è errato (ad es. "--select region--" w.value="" )
  • quando il valore di ng-model è errato e l'utente apre il menu a discesa delle opzioni, il segnaposto viene selezionato (altre soluzioni menzionate qui fanno apparire selezionata la prima opzione che può essere fuorviante)
  • consentire all'utente di deselezionare un valore valido, essenzialmente selezionando nuovamente il valore errato / predefinito

inserisci qui la descrizione dell'immagine

codice

<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

Domande e risposte originali - https://stackoverflow.com/a/32880941/1121919


Vuoi dire se il valore predefinito è <option ng-selected="true" value="null">?
jusopi,

Voglio dire se il valore del modello ng è impostato come null, crea angolare e opzione vuota sulla selezione
Flezcano

16

Una soluzione rapida:

select option:empty { display:none }

Spero che aiuti qualcuno. Idealmente, la risposta selezionata dovrebbe essere l'approccio, ma se nel caso ciò non fosse possibile, dovrebbe funzionare come una patch.


2
Per i miei test questo funzionerà solo su Chrome (nuovo Chrome, oltre a quello) e Firefox. IE e Safari break. Non so di opera e altri browser perimetrali. Ad ogni modo, questa non è una buona soluzione, sfortunatamente.
Dudewad,

dove dovremmo inserirlo in html prima della chiusura di <select> oppure in js
H Varma l'

1
@HVarma È una regola CSS. Inseriscilo nel foglio di stile o all'interno del tag <style>
KK

@KK stackoverflow.com/questions/48355599/... Potete per favore controllare questo?
Sudarshan Kalebere,

14

Sì ng-model creerà un valore di opzione vuoto, quando la proprietà ng-model non è definita. Possiamo evitarlo, se assegniamo un oggetto a ng-model

Esempio

codifica angolare

$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>

Nota importante:

Assegna l'oggetto dell'array come $ scope.collections [0] o $ scope.collections [1] a ng-model, non usare le proprietà dell'oggetto. se si ottiene il valore dell'opzione di selezione dal server, utilizzando la funzione di richiamata, assegnare l'oggetto a ng-model

NOTA dal documento angolare

Nota: ngModel confronta per riferimento, non per valore. Questo è importante quando si esegue il binding a una matrice di oggetti. vedi un esempio http://jsfiddle.net/qWzTb/

ho provato molte volte finalmente l'ho trovato.


8

Sebbene le risposte di @ pkozlowski.opensource e @ Mark siano corrette, mi piacerebbe condividere la mia versione leggermente modificata in cui seleziono sempre il primo elemento nell'elenco, indipendentemente dal suo valore:

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

4

Sto usando Angular 1.4x e ho trovato questo esempio, quindi ho usato ng-init per impostare il valore iniziale nella selezione:

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

3


Ho affrontato lo stesso problema. Se stai pubblicando una forma angolare con posta normale, dovrai affrontare questo problema, poiché angolare non ti consente di impostare i valori per le opzioni nel modo in cui hai usato. Se ottieni il valore di "form.type", troverai il valore giusto. Devi pubblicare l'oggetto angolare da solo, non il modulo post.


3

Una soluzione semplice è quella di impostare un'opzione con un valore vuoto che ""ho trovato questo elimina l'opzione extra non definita.


5
Doenst funziona @ 1.4.3, aggiunge solo 2 opzioni vuote al modulo
Denny Mueller,

3

Ok, in realtà la risposta è molto semplice: quando c'è un'opzione non riconosciuta da Angular, ne include una noiosa. Quello che stai facendo di sbagliato è, quando usi ng-options, legge un oggetto, diciamo[{ id: 10, name: test }, { id: 11, name: test2 }] right?

Questo è ciò che deve essere il valore del tuo modello per valutarlo come uguale, ad esempio vuoi che il valore selezionato sia 10, devi impostare il tuo modello su un valore come { id: 10, name: test } selezionare 10, quindi NON creerà quel cestino.

Spero che possa aiutare tutti a capire, ho avuto un brutto momento a provare :)


2

Questa soluzione funziona per me:

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

Il downvote potrebbe essere dovuto al fatto che l'applicazione dei CSS agli elementi delle opzioni non funziona su tutti i browser.
Kafoso,

L'ho appena testato su Chrome, FireFox, Safari e Edge: tutto funziona.
MMM,

@MMM "tutti i browser" include IE. Molti utenti sono ancora bloccati con IE 10 e 11, ed è probabilmente il motivo per cui è avvenuta la votazione negativa. Chrome, fF, Saf e Edge non sono "tutti i browser".
PKD,

1

Questo ha funzionato per me

<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>

Aggiunge semplicemente l'opzione all'elenco e lascia tristemente lo spazio vuoto.
AMontpetit,

1

Funziona perfettamente

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

il modo in cui funziona è che questo dà la prima opzione da visualizzare prima di selezionare qualcosa e lo display:nonerimuove dal menu a discesa, quindi se vuoi puoi farlo

<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>

e questo ti darà il select and optionprima di selezionare ma una volta selezionato scomparirà e non verrà visualizzato nel menu a discesa.


In realtà non rispondi alla domanda stessa, peggio ancora, stai solo nascondendo l'elemento.
Marco,

0

Prova questo nel tuo controller, nello stesso ordine:

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

Ho provato il tuo metodo ma sfortunatamente non sono riuscito a farlo funzionare. Puoi dare un'occhiata a questo violino. jsfiddle.net/5PdaX
Aniket Sinha,

0

Ecco la soluzione:

per un campione di dati come:

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

L'opzione di selezione dovrebbe essere così: -

<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>

Il punto è che quando scriviamo value.listCountcome value.listName, popola automaticamente il testo value.listNamema il valore dell'opzione selezionata è value.listCountsebbene i valori mostrino normali 0,1,2 .. e così via !!!

Nel mio caso, financeRef.financeLimitsta effettivamente afferrando value.listCounte posso fare la mia manipolazione nel controller in modo dinamico.


0

Vorrei aggiungere che se il valore iniziale proviene da un'associazione da qualche elemento genitore o componente 1.5, assicurarsi che venga passato il tipo corretto. Se si utilizza @in associazione, la variabile passata sarà stringa e se le opzioni sono ad es. numeri interi quindi verrà visualizzata l'opzione vuota.

Analizzare correttamente il valore in init oppure eseguire il binding con <e non @(meno consigliato per le prestazioni se non necessario).


0

Soluzione semplice

<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

Una soluzione grind con jQuery quando non hai il controllo delle opzioni

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, qualcuno ti ha retrocesso perché questa è una soluzione jQuery, non AngularJs
Mawg dice di ripristinare Monica il

Si pone la domanda di scavare di più su Angular ...: - /
Sahu V Kumar

0

Se usi ng-init il tuo modello per risolvere questo problema:

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

0

ho avuto lo stesso problema, ho (rimosso "ng-model") cambiato questo:

<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>

a questo:

<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>

ora funziona, ma nel mio caso è stato causato che ho eliminato quell'ambito da ng.controller, controlla se non hai fatto lo stesso.



0

L'unica cosa che ha funzionato per me è usare track byin ng-options, in questo modo:

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


se uso questo ng-optionottenere ultimo valore dell'array cui voglio valore impostato di optiondi select. Non ha risolto :(
rufatZZ il

0

Fai riferimento all'esempio della documentazione di angularjs su come superare questi problemi.

  1. Vai a questo link di documentazione qui
  2. Trova " Binding seleziona un valore non stringa tramite analisi / formattazione ngModel "
  3. Qui puoi vedere, la direttiva chiamata ' convertToNumber ' risolve il problema.

Per me funziona. Puoi anche vedere come funziona qui


0

Possiamo usare CSS per nascondere la prima opzione, ma non funzionerà in IE 10, 11. Il modo migliore è rimuovere l'elemento usando Jquery. Questa soluzione funziona per i principali browser testati in Chrome e IE10, 11

Anche se stai usando angolare, a volte usando setTimeout funziona

$scope.RemoveFirstOptionElement = function (element) {
    setTimeout(function () {
        $(element.children()[0]).remove();
    }, 0);
};
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.