¿Por qué AngularJS incluye una opción vacía en select?


652

He estado trabajando con AngularJS durante las últimas semanas, y lo único que realmente me molesta es que incluso después de probar todas las permutaciones o la configuración definida en la especificación en http://docs.angularjs.org/api/ng .directive: select , sigo teniendo una opción vacía como primer elemento secundario del elemento select.

Aquí está el jade:

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

Aquí el controlador:

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

Finalmente, aquí está el HTML que se genera:

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

¿Qué necesito hacer para deshacerme de él?

PD: Las cosas funcionan sin esto también, pero parece extraño si usas select2 sin selección múltiple.

Respuestas:


646

El vacío optionse genera cuando un valor al que ng-modelhace referencia no existe en un conjunto de opciones pasado a ng-options. Esto sucede para evitar la selección accidental del modelo: AngularJS puede ver que el modelo inicial no está definido o no está en el conjunto de opciones y no quiere decidir el valor del modelo por sí solo.

Si desea deshacerse de la opción vacía, simplemente seleccione un valor inicial en su controlador, algo como:

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

Aquí está el jsFiddle: http://jsfiddle.net/MTfRD/3/

En resumen: la opción vacía significa que no se selecciona ningún modelo válido (por válido quiero decir: del conjunto de opciones). Debe seleccionar un valor de modelo válido para deshacerse de esta opción vacía.


77
Lo intenté con ambos $ scope.form.type = ''; y $ scope.form.type = $ scope.typeOptions [0], sin embargo, sigo viendo esto - <option value = "?" selected = "selected"> </option>
Sudhanshu

55
A veces realmente no tiene sentido tener estos datos en el JS. Si fue el servidor el que tomó la decisión sobre lo que estaba en esa selección, ¿por qué el JS debería duplicarlo?
heneryville

11
Desafortunadamente, esto no funciona si está utilizando una matriz y nulles uno de sus valores.
vpiTriumph

66
¿Es posible agregar un texto dentro del vacío <option>para que angular genere algo así<option value="?">Select an option</option>
RPDeshaies

3
@ Tareck117 solo wirte que <option value="">Select an option</option>es el valor nulo de la lista de opciones. No hay necesidad de caracteres?
Sebastian

235

Si desea un valor inicial, consulte la respuesta de @ pkozlowski.opensource, que para su información también se puede implementar en la vista (en lugar de en el controlador) 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>

Si no desea un valor inicial, "un solo elemento codificado, con el valor establecido en una cadena vacía, puede anidarse en el elemento. Este elemento representará una opción nula o" no seleccionada ":

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

44
@hugo, violín de trabajo: jsfiddle.net/4qKyx/1 Tenga en cuenta que se muestra "seleccionar un tipo", pero no hay ningún valor asociado. Y una vez que seleccione otra cosa, no la volverá a ver. (Prueba en Chrome.)
Mark Rajcok

1
@MarkRajcok - ¡excelente sugerencia! Me he topado con otro problema usando su ejemplo con la directiva translúcida. ¿Podrías echar un vistazo? plnkr.co/edit/efaZdEQlNfoDihk1R1zc?p=preview
Jan-Terje Sørensen

2
El problema con esto es que aún puede seleccionar con el teclado, consulte la solución stackoverflow.com/a/8442831/57344
HaveAGuess el

2
Esto puede funcionar por ahora, pero la documentación angular específicamente recomienda no usar ng-init para nada más que ng-repeat - ver docs.angularjs.org/api/ng/directive/ngInit
Ed Norris

3
No funciona en IE10, el "seleccionar un tipo" siempre está visible y seleccionable.
Robin

121

Angular <1.4

Para cualquiera que trate "nulo" como un valor válido para una de las opciones (así que imagine que "nulo" es un valor de uno de los elementos en typeOptions en el ejemplo a continuación), encontré esa forma más simple de asegurarme de que se agregue automáticamente La opción oculta es usar ng-if.

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

¿Por qué ng-if y no ng-hide? Debido a que desea que los selectores CSS que apunten a la primera opción dentro de arriba, seleccione la opción "real", no la que está oculta. Se vuelve útil cuando usa transportador para pruebas e2e y (por cualquier razón) usa by.css () para seleccionar opciones de selección.

Angular> = 1.4

Debido a la refactorización de las directivas select y options, el uso ng-ifya no es una opción viable, por lo que debe recurrir para que vuelva a ng-show="false"funcionar.


55
Debería ser la respuesta aceptada, porque este es el comportamiento visual correcto para la selección. ¡ size="5"Pones los atributos seleccionados y puedes ver que no hay nada seleccionado! Como en un elemento predeterminado <select>! No puedo entender por qué angular está haciendo tal cosa para selecciones sin multipleatributo ...
Sebastian

1
Sí, estoy de acuerdo, esta debería ser la respuesta aceptada. Esta es la 'forma angular'. ng-if realmente elimina el elemento de opciones del dom (cuando es falso), por lo que esta solución también funciona en todos los navegadores sin codificación 'hacky' (al contrario de ng-hide o ng-show).
Sander_P

2
@Sander_P, por definición, esta solución es codificación "hacky" en mi opinión (poner algo en el dom para engañar angularmente para sacarla), pero tienes razón, sigue siendo la "mejor" solución. ¡La solución "aún mejor" sería permitir una selección friggin que no tiene valor! ¿Que demonios? No es así es un escenario de borde.
dudewad

@dudewad: las cosas podrían funcionar mejor con Angular 1.4. De los AngularJS blog para 1.4.0: "ngOptions se refactorizado por completo para permitir que un número de insectos molestos por determinar,"
Sander_P

1
Jaja "bichos molestos". Bueno. Bueno, todavía estoy un poco vacilante cuando se trata de actualizar 3 días antes de la entrega, así que seguiré con su solución por ahora, que parece estar funcionando a la perfección. Sin embargo, señaló para el futuro :) ¡Gracias!
dudewad

36

Quizás útil para alguien:

Si desea utilizar opciones simples en lugar de ng-options, puede hacer lo siguiente:

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

Establecer el modelo en línea. Use ng-init para deshacerse de la opción vacía


No he podido encontrar un ejemplo claro de configuración de opciones ng con OBJETOS en lugar de matrices JSON y cuando trato de "traducir" entre los dos, no solo no sale bien sino que falla "en silencio", así que No tengo idea de lo que estoy haciendo mal. Finalmente opté por ng-repeat simple en una etiqueta de opción. Sé que no es la mejor práctica, pero al menos FUNCIONA. Si alguien puede señalarme un ejemplo de TRABAJO sencillo, fácil de cambiar en los detalles, angular-n00b-amigable usando ng-options con objetos de datos (NO JSON), estaría eufórico. Doble euforia si usa ng-init también.
code-sushi

Estoy usando opciones simples, pero en el controlador no parece obtener el valor del menú desplegable seleccionado. Ej: Intenté alertar ($ scope.sortorder.value); y alerta ($ scope.sortorder); ambos dan indefinido. ¿Cómo obtener el valor seleccionado aquí?
Maverick Riz

Muchas gracias por esto. Estaba a punto de escribir un objeto completamente inútil en el controlador que no necesitaba. Solo necesitaba una selección simple ... Gracias una vez más.
Muhammad bin Yusrat

22

Algo similar me estaba sucediendo a mí también y fue causado por una actualización a angular 1.5. ng-initparece estar siendo analizado por tipo en versiones más nuevas de Angular. En Angular anterior, se asignaría ng-init="myModelName=600"a una opción con el valor "600", es decir, <option value="600">First</option>pero en Angular 1.5 no encontrará esto, ya que parece esperar encontrar una opción con el valor 600, es decir <option value=600>First</option>. Angular luego insertaría un primer elemento aleatorio:

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

Angular <1.2.x

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

Angular> 1.2

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

1
¡Gracias! En mi caso, no puedo usar ng-init (sin valor predeterminado), así que fundí mi modelo en una cadena y funcionó.
Rodrigo Graça el

Muy útil para mi problema de producción de aplicaciones. Gracias @Nabil Boag
Venki

3
Esto funciona, claro, pero la mejor opción es usar ng-value="600"en optionlugar de value. Lo analizará a un número y no tiene que convertir sus valores como lo hace ahora :)
Max

@Max Probé muchas respuestas de alto valor, pero ninguna funcionó hasta que encontré la tuya. Gracias.
Andrew

21

Entre la multitud de respuestas aquí, pensé que volvería a publicar la solución que funcionó para mí y cumplí con todas las siguientes condiciones:

  • proporcionó un marcador de posición / solicitud cuando el modelo ng es falso (por ejemplo, "--seleccionar región--" w. value="")
  • cuando el valor del modelo ng es falso y el usuario abre el menú desplegable de opciones, se selecciona el marcador de posición (otras soluciones mencionadas aquí hacen que la primera opción aparezca seleccionada, lo que puede ser engañoso)
  • Permitir al usuario anular la selección de un valor válido, esencialmente seleccionando nuevamente el valor falso / predeterminado

ingrese la descripción de la imagen aquí

código

<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

Preguntas y respuestas originales: https://stackoverflow.com/a/32880941/1121919


¿Quieres decir si el valor predeterminado es <option ng-selected="true" value="null">?
jusopi

Quiero decir, si el valor del modelo ng se establece como nulo, crea angular y la opción vacía en la selección
Flezcano

16

Una solución rápida:

select option:empty { display:none }

Espero que ayude a alguien. Idealmente, la respuesta seleccionada debería ser el enfoque, pero si eso no es posible, entonces debería funcionar como un parche.


2
Según mis pruebas, esto solo funcionará en Chrome (nuevo Chrome, además de eso) y Firefox. Escapada de IE y Safari. No sé acerca de la ópera y otros navegadores de borde. De cualquier manera, esta no es una buena solución, desafortunadamente.
dudewad

¿dónde deberíamos colocar eso en html antes del cierre de <select> o bien en el js
H Varma

1
@HVarma Es una regla CSS. Colóquelo en la hoja de estilo o dentro de la etiqueta <style>
KK


14

Sí, ng-model creará un valor de opción vacío, cuando la propiedad ng-model no está definida. Podemos evitar esto si asignamos un objeto a ng-model

Ejemplo

codificación angular

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

Asigne el objeto de la matriz como $ scope.collections [0] o $ scope.collections [1] a ng-model, no use las propiedades del objeto. si obtiene el valor de opción de selección del servidor, utilizando la función de devolución de llamada, asigne un objeto a ng-model

NOTA del documento angular

Nota: ngModel compara por referencia, no por valor. Esto es importante cuando se vincula a una matriz de objetos. ver un ejemplo http://jsfiddle.net/qWzTb/

Lo he intentado muchas veces, finalmente lo encontré.


8

Aunque las respuestas de @ pkozlowski.opensource y @ Mark son correctas, me gustaría compartir mi versión ligeramente modificada donde siempre selecciono el primer elemento de la lista, independientemente de su valor:

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

4

Estoy usando Angular 1.4x y encontré este ejemplo, así que usé ng-init para establecer el valor inicial en la selección:

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

3


Me enfrenté al mismo problema. Si está publicando una forma angular con publicación normal, entonces se enfrentará a este problema, ya que angular no le permite establecer valores para las opciones en la forma en que lo ha utilizado. Si obtiene el valor de "form.type", encontrará el valor correcto. Debe publicar el objeto angular en sí mismo, no el formulario de publicación.


3

Una solución simple es establecer una opción con un valor en blanco "". Encontré que esto elimina la opción indefinida adicional.


55
Doenst work @ 1.4.3, solo agrega 2 opciones vacías al formulario
Denny Mueller

3

Ok, en realidad la respuesta es muy simple: cuando hay una opción no reconocida por Angular, incluye una aburrida. Lo que estás haciendo mal es que, cuando usas ng-options, lee un objeto, por ejemplo[{ id: 10, name: test }, { id: 11, name: test2 }] right?

Esto es lo que debe ser el valor de su modelo para evaluarlo como igual, digamos que desea que el valor seleccionado sea 10, debe establecer su modelo en un valor como { id: 10, name: test }para seleccionar 10, por lo tanto, NO creará esa basura.

Espero que ayude a todos a entender, me costó mucho intentarlo :)


2

Esta solución me funciona:

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

El voto negativo podría deberse a que aplicar CSS a los elementos de opción no funciona en todos los navegadores.
Kafoso

Lo acabo de probar en Chrome, Firefox, Safari y Edge: todo funciona.
MMM

@MMM "todos los navegadores" incluye IE. Muchos usuarios todavía están atrapados con IE 10 y 11, y es por eso que ocurrió el voto negativo. Chrome, fF, Saf y Edge no son "todos los navegadores".
PKD

1

Esto funciono para mi

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

Simplemente agrega la opción a la lista y deja el espacio vacío, lamentablemente.
AMontpetit

1

Esto funciona perfectamente 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 forma en que funciona es que esto le da la primera opción que se mostrará antes de seleccionar algo y lo display:noneelimina del menú desplegable, por lo que si lo desea, puede hacerlo

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

y esto le dará select and optionantes de seleccionar, pero una vez seleccionado, desaparecerá y no aparecerá en el menú desplegable.


En realidad no respondes la pregunta en sí, peor que eso, solo estás ocultando el elemento.
Marco

0

Pruebe este en su controlador, en el mismo orden:

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

Probé tu método pero desafortunadamente no pude hacerlo funcionar. ¿Puedes echar un vistazo a este violín? jsfiddle.net/5PdaX
Aniket Sinha

0

Aquí está la solución:

para una muestra de datos como:

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

La opción de selección debería ser así:

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

El punto es que cuando escribimos value.listCountcomo value.listName, automáticamente rellena el texto, value.listNamepero el valor de la opción seleccionada es, value.listCountaunque los valores pueden mostrar normal 0,1,2 ... ¡¡¡y así sucesivamente !!!

En mi caso, el financeRef.financeLimitrealmente está agarrando el value.listCounty puedo hacer mi manipulación en el controlador de forma dinámica.


0

Me gustaría agregar que si el valor inicial proviene de un enlace de algún elemento padre o componente 1.5, asegúrese de que se pase el tipo correcto. Si se usa @en enlace, la variable pasada será string y si las opciones son, por ejemplo. enteros, entonces aparecerá la opción vacía.

Analice correctamente el valor en init, o enlace con <y no @(menos recomendado para el rendimiento a menos que sea necesario).


0

Solución 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

Una solución de rutina con jQuery cuando no tienes el control de las opciones

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, alguien te rechazó porque esta es una solución jQuery, no AngularJs
Mawg dice que reinstalar a Monica el

La pregunta se hace para sacar más de Angular ...: - /
Sahu V Kumar

0

Si usa ng-init su modelo para resolver este problema:

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

0

tuve el mismo problema, yo (eliminé "ng-model") cambié esto:

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

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

ahora funciona, pero en mi caso fue porque eliminé ese alcance de ng.controller, verifique si no hizo lo mismo.



0

Lo único que funcionó para mí es usarlo track byde ng-optionsesta manera:

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


si uso esto ng-optionobtengo el último valor de la matriz que quiero establecer el valor optionde select. No se resolvió :(
rufatZZ

0

Consulte el ejemplo de la documentación de angularjs sobre cómo superar estos problemas.

  1. Ir a este enlace de documentación aquí
  2. Encuentre ' Binding select a un valor que no sea de cadena a través de ngModel parsing / formatting '
  3. Allí puedes ver, la directiva llamada ' convertToNumber ' resuelve el problema.

Esto funciona para mi. También puede ver cómo funciona aquí


0

Podemos usar CSS para ocultar la primera opción, pero no funcionará en IE 10, 11. La mejor manera es eliminar el elemento usando Jquery. Esta solución funciona para los principales navegadores probados en Chrome e IE10, 11

Además, si está usando angular, a veces usar setTimeout funciona

$scope.RemoveFirstOptionElement = function (element) {
    setTimeout(function () {
        $(element.children()[0]).remove();
    }, 0);
};
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.