Почему AngularJS включает пустую опцию в select?


652

Я работаю с AngularJS в течение последних нескольких недель, и одна вещь, которая меня действительно беспокоит, это то, что даже после попытки всех перестановок или конфигурации, определенной в спецификации на http://docs.angularjs.org/api/ng .directive: select , я все еще получаю пустую опцию в качестве первого дочернего элемента select.

Вот Джейд:

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

Вот контроллер:

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

Наконец, вот HTML, который генерируется:

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

Что мне нужно сделать, чтобы избавиться от этого?

PS: Вещи работают и без этого, но это выглядит странно, если вы используете select2 без множественного выбора.

Ответы:


646

Пустой optionгенерируется, когда значение, на которое ссылается, ng-modelне существует в наборе параметров, переданныхng-options . Это происходит для предотвращения случайного выбора модели: AngularJS может видеть, что исходная модель либо не определена, либо отсутствует в наборе параметров, и не хочет самостоятельно определять значение модели.

Если вы хотите избавиться от пустой опции, просто выберите начальное значение в вашем контроллере, например:

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

Вот jsFiddle: http://jsfiddle.net/MTfRD/3/

Вкратце: пустая опция означает, что ни одна действительная модель не выбрана (под действительной я имею в виду: из набора опций). Вам нужно выбрать правильное значение модели, чтобы избавиться от этой пустой опции.


7
Я пытался с обоими $ scope.form.type = ''; и $ scope.form.type = $ scope.typeOptions [0], однако я все еще вижу это - <option value = "?" selected = "selected"> </ option>
Sudhanshu

5
Иногда на самом деле не имеет смысла хранить эти данные в JS. Если именно сервер принял решение о том, что было в этом выборе, почему JS должен его дублировать?
Heneryville

11
К сожалению, это не работает, если вы используете массив и nullявляется одним из ваших значений.
vpiTriumph

6
Можно ли добавить текст внутри пустого, <option>так что тат угловатый сгенерировал что-то вроде<option value="?">Select an option</option>
RPDeshaies

3
@ Tareck117 просто Wirte, который <option value="">Select an option</option>является нулевым значением в списке параметров. Нет необходимости в? -Характере.
Себастьян

235

Если вам нужно начальное значение, см. Ответ @ pkozlowski.opensource, какой FYI также можно реализовать в представлении (а не в контроллере) с помощью 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>

Если вам не нужно начальное значение, «в элемент может быть вложен один жестко запрограммированный элемент со значением, установленным в пустую строку. Этот элемент будет представлять нулевую или« не выбранную »опцию»:

<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, рабочая скрипка: jsfiddle.net/4qKyx/1 Обратите внимание, что «выберите тип», но с ним не связано значение. И как только вы выберете что-то другое, вы больше этого не увидите. (Тест на Chrome.)
Марк Райкок,

1
@MarkRajcok - отличное предложение! я наткнулся на другую проблему, используя ваш пример с включающей директивой. Не могли бы вы взглянуть? plnkr.co/edit/efaZdEQlNfoDihk1R1zc?p=preview
Ян-Терье Соренсен

2
Проблема в том, что вы все еще можете выбрать с клавиатуры, см. Решение stackoverflow.com/a/8442831/57344
HaveAGuess

2
Пока это может сработать, но документация по угловым направлениям особо рекомендует не использовать ng-init для чего-либо, кроме ng-repeat - см. Docs.angularjs.org/api/ng/directive/ngInit
Эд Норрис

3
Не работает в IE10, «выбрать тип» всегда виден и выбирается.
Робин

121

Угловой <1.4

Для всех, кто рассматривает «null» как допустимое значение для одного из параметров (поэтому представьте, что «null» - это значение одного из элементов в typeOptions в примере ниже), я нашел этот простой способ убедиться, что автоматически добавлено опция скрыта - это использовать ng-if.

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

Почему нг-если, а не нг-скрыть? Поскольку вы хотите, чтобы селекторы css были нацелены на первый вариант внутри, выберите таргетинг на «реальный» вариант, а не тот, который скрыт. Это становится полезным, когда вы используете транспортир для тестирования e2e и (по любой причине) вы используете by.css () для выбора параметров.

Угловой> = 1.4

Из-за рефакторинга директив select и options использование ng-ifбольше не является жизнеспособным вариантом, поэтому вам нужно обратиться к нему, ng-show="false"чтобы оно снова заработало.


5
Должен быть принятый ответ, потому что это правильное визуальное поведение для выбора. Вы помещаете size="5"в атрибуты selects и видите, что ничего не выбрано! Как в <select>элементе по умолчанию -элемент! Я не могу понять, почему angular делает такую ​​вещь для селектов без multipleатрибута ...
Себастьян,

1
Да, я согласен, это должен быть принятый ответ. Это «угловой путь». ng-if фактически удаляет элемент options из dom (когда false), поэтому это решение также работает во всех браузерах без «хакерского» кодирования (в отличие от ng-hide или ng-show).
Sander_P

2
@Sander_P, по определению, это решение, на мой взгляд, является «хакерским» кодированием (что-то вводит в заблуждение, чтобы обманным путем вывести его из строя), но вы правы, это все еще является «лучшим» решением. «Еще лучше» решение было бы позволить чертовски выбрать, который не имеет значения! Какого черта? Это не так, как это крайний сценарий.
dudewad

@dudewad: все может работать лучше с Angular 1.4. Из блога AngularJS для 1.4.0: «ngOptions был полностью реорганизован, чтобы можно было исправлять ряд надоедливых ошибок»
Sander_P

1
Хаха "досадные жучки". Ладно. Ну, я все еще немного занудный, когда дело доходит до обновления за 3 дня до доставки, так что я пока остановлюсь на вашем решении, которое, кажется, работает беспроблемно. Отмечено на будущее, хотя :) Спасибо!
dudewad

36

Может быть, кому-то пригодится:

Если вы хотите использовать обычные параметры вместо ng-options, вы можете сделать следующее:

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

Установите модель в линию. Используйте ng-init, чтобы избавиться от пустой опции


Я не смог найти четкого примера настройки параметров ng с OBJECTS, а не с массивами JSON, и когда я пытаюсь «перевести» между ними, он не только не работает правильно, но и «молча», поэтому не получается Я понятия не имею, что я делаю неправильно. Я наконец выбрал простой ng-repeat в теге option. Я знаю, что это не лучшая практика, но, по крайней мере, это работает. Если кто-то может указать мне на простой, легко заменяемый на детали, дружественный к angular-n00b РАБОЧИЙ пример, использующий опции ng с объектами данных (НЕ JSON), я был бы в восторге. Удваивается, если он также использует ng-init.
код суши

Я использую простые параметры, но в контроллере я не получаю значение выбранного выпадающего списка. Пример: я пробовал оповещение ($ scope.sortorder.value); и оповещение ($ scope.sortorder); оба дают неопределенные. Как получить выбранное значение здесь?
Маверик Риз

Спасибо тебе большое за это. Я собирался написать совершенно бесполезный объект в контроллере, который мне не нужен, мне просто нужно было просто выбрать. Спасибо еще раз.
Мухаммед бин Юсрат

22

Нечто подобное происходило и со мной и было вызвано обновлением до угловой версии 1.5. ng-initКажется, в новых версиях Angular выполняется синтаксический анализ типа . В старшем угловом ng-init="myModelName=600"будет отображаться в качестве опции со значением «600» , то есть , <option value="600">First</option>но в угловому 1.5 он не найдет это , как это , кажется, рассчитывая найти вариант со значением 600 т <option value=600>First</option>. Затем Angular вставит случайный первый элемент:

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

Угловой <1.2.x

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

Угловой> 1.2

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

1
Спасибо! В моем случае я не могу использовать ng-init (без значения по умолчанию), поэтому я преобразовал свою модель в строку, и это сработало!
Родриго Граса

Очень полезный для моей проблемы производства приложений. Благодаря @Nabil Boag
Venki

3
Это работает, конечно, но тем лучше варианты, чтобы использовать ng-value="600"в optionвместо value. Он будет разбирать его на число, и вам не нужно конвертировать ваши значения, как сейчас :)
Макс

@ Макс Я пробовал много ценных ответов, но ни один не помог, пока я не нашел твои. Спасибо.
Андрей

21

Среди множества ответов здесь я решил опубликовать решение, которое сработало для меня, и выполнить все следующие условия:

  • предоставил заполнитель / подсказку, когда ng-модель ложна (например, "--select region--" w. value="")
  • когда значение ng-модели ложно, и пользователь открывает раскрывающийся список параметров, выбирается местозаполнитель (другие решения, упомянутые здесь, делают первый параметр выбранным, что может вводить в заблуждение)
  • Позволяет пользователю отменить выбор действительного значения, по существу, снова выбирая ложное значение / значение по умолчанию

введите описание изображения здесь

код

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

ЦСИ

оригинальные вопросы и ответы - https://stackoverflow.com/a/32880941/1121919


Вы имеете в виду, если по умолчанию <option ng-selected="true" value="null">?
Юзопи

Я имею в виду, если значение ng-модели установлено как нулевое, угловое создание и пустая опция выбора
Flezcano

16

Быстрое решение:

select option:empty { display:none }

Надеюсь, это кому-нибудь поможет. В идеале выбранный ответ должен быть подходом, но если в случае, если это невозможно, то должен работать как патч.


2
По моим тестам, это будет работать только в Chrome (новый Chrome, кроме того) и Firefox. IE и Safari ломаются. Не знаю об опере и других браузерах. В любом случае, это не очень хорошее решение, к сожалению.
dudewad

где мы должны поместить это в html до закрытия <select> или в js
H Varma

1
@HVarma Это правило CSS. Поместите его в таблицу стилей или в тег <style>
KK

@KK stackoverflow.com/questions/48355599/… Можете ли вы проверить это?
Сударшан Калебере

14

Да, ng-модель создаст пустое значение опции, когда свойство ng-модели неопределено. Мы можем избежать этого, если мы назначим объект для ng-модели

пример

угловое кодирование

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

Важная заметка:

Присвойте объект массива как $ scope.collections [0] или $ scope.collections [1] для ng-модели, не используйте свойства объекта. если вы получаете значение параметра select с сервера, используя функцию обратного вызова, присвойте объект ng-модели

ПРИМЕЧАНИЕ от углового документа

Примечание: ngModel сравнивает по ссылке, а не по значению. Это важно при привязке к массиву объектов. см. пример http://jsfiddle.net/qWzTb/

Я пытался много раз, наконец, я нашел это.


8

Хотя ответы @ pkozlowski.opensource и @ Mark верны, я хотел бы поделиться своей слегка измененной версией, где я всегда выбираю первый элемент в списке, независимо от его значения:

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

4

Я использую Angular 1.4x, и я нашел этот пример, поэтому я использовал ng-init, чтобы установить начальное значение в select:

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

3


Я столкнулся с той же проблемой. Если вы публикуете угловую форму с обычной публикацией, то вы столкнетесь с этой проблемой, так как угловая форма не позволяет вам устанавливать значения для параметров, которые вы использовали. Если вы получите значение «form.type», то вы найдете правильное значение. Вы должны разместить угловой объект сам, а не форму сообщения.


3

Простое решение состоит в том, чтобы установить опцию с пустым значением. ""Я обнаружил, что это устраняет лишнюю неопределенную опцию.


5
Doenst work @ 1.4.3, он просто добавляет 2 пустые опции в форму
Денни Мюллер

3

Хорошо, на самом деле ответ очень прост: когда есть опция, не распознаваемая Angular, она включает тусклую. Что вы делаете неправильно, когда вы используете ng-options, он читает объект, скажем[{ id: 10, name: test }, { id: 11, name: test2 }] right?

Это то, чем должно быть значение вашей модели, чтобы оценить его как равное, скажем, вы хотите, чтобы выбранное значение было равно 10, вам нужно установить для вашей модели значение, подобное { id: 10, name: test }выбору 10, поэтому она НЕ будет создавать этот мусор.

Надеюсь, это поможет всем понять, я очень старался :)


2

Это решение работает для меня:

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

Downvote может быть связано с тем, что применение CSS к элементам option работает не во всех браузерах.
Кафосо

Я только что проверил это на Chrome, FireFox, Safari и Edge - все работает.
МММ

@MMM "все браузеры" включает в себя IE. Многие пользователи все еще привязаны к IE 10 и 11, и, вероятно, именно поэтому произошло снижение. Chrome, fF, Saf и Edge - это не все браузеры.
ДОК

1

Это сработало для меня

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

Просто добавляет опцию в список и, к сожалению, оставляет пустое место.
AMontpetit

1

Это прекрасно работает

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

способ, которым это работает, состоит в том, что это дает первую опцию, которая будет отображаться перед выбором чего-либо, и display:noneудаляет ее из выпадающего списка, так что если вы хотите, вы можете сделать

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

и это даст вам select and option перед выбором, но после выбора он исчезнет, ​​и он не будет отображаться в раскрывающемся списке.


На самом деле вы не отвечаете на сам вопрос, что еще хуже, вы просто скрываете элемент.
Марко

0

Попробуйте это в вашем контроллере, в том же порядке:

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

Я попробовал ваш метод, но, к сожалению, я не смог заставить его работать. Можете ли вы взглянуть на эту скрипку? jsfiddle.net/5PdaX
Аникет Синха

0

Вот исправление:

для образца данных, таких как:

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

Опция выбора должна быть такой:

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

Суть в том, что когда мы пишем value.listCountкак value.listName, он автоматически заполняет текст, value.listNameно значение выбранной опции равно, value.listCountхотя значения мои показывают нормальные 0,1,2 .. и так далее !!!

В моем случае, financeRef.financeLimitэто фактически захват, value.listCountи я могу динамически манипулировать контроллером.


0

Я хотел бы добавить, что если начальное значение исходит из привязки какого-либо родительского элемента или компонента 1.5, убедитесь, что передан правильный тип. Если используется @в связывании, переданная переменная будет строкой, и если параметры, например,. целые числа, тогда появится пустая опция.

Либо правильно анализируйте значение в init, либо связывайте с <и нет @(менее рекомендуется для производительности, если в этом нет необходимости).


0

Простое решение

<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

Решение для измельчения с помощью jQuery, когда у вас нет контроля над параметрами

HTML:

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

ЯШ:

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

Паскаль, кто-то отказался от вас, потому что это решение jQuery, а не AngularJs,
говорит Моуг, восстановите Monica

Вопрос задается, чтобы выкопать больше Angular ...: - /
Sahu V Kumar

0

Если вы используете ng-init вашу модель для решения этой проблемы:

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

0

у меня была такая же проблема, я (убрал "ng-модель") изменил это:

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

к этому:

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

теперь это работает, но в моем случае это было причиной того, что я удалил эту область из ng.controller, проверьте, не делали ли вы то же самое.


0

Привет, у меня было несколько мобильных ссылок jQUery, и я их удалил. С jQuery mobile у меня не работало ни одно из вышеперечисленных исправлений. (Здорово, если кто-то может объяснить конфликт между jQuery Mobile и Angular JS)

https://guntucomputerhacks.blogspot.com.au/2017/10/angular-js-drop-down-first-options-vs.html


0

Единственное, что сработало для меня, это использование track byв ng-options, вот так:

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


если я использую это ng-optionполучить последнее значение массива , который я хочу , чтобы установленное значение optionиз select. Это не решено :(
rufatZZ

0

Обратитесь к примеру из документации angularjs, как преодолеть эти проблемы.

  1. Перейдите по этой ссылке документации здесь
  2. Найти ' Binding select к нестроковому значению с помощью синтаксического анализа / форматирования ngModel '
  3. Там вы можете видеть, что директива с именем convertToNumber решает проблему.

Меня устраивает. Также можете посмотреть, как это работает здесь


0

Мы можем использовать CSS, чтобы скрыть первый вариант, но он не будет работать в IE 10, 11. Лучший способ - удалить элемент с помощью Jquery. Это решение работает для основных браузеров, протестированных в Chrome и IE10, 11

Также, если вы используете угловой, иногда работает setTimeout

$scope.RemoveFirstOptionElement = function (element) {
    setTimeout(function () {
        $(element.children()[0]).remove();
    }, 0);
};
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.