Dlaczego AngularJS zawiera pustą opcję w select?

652

Pracuję z AngularJS przez ostatnie kilka tygodni i jedyne, co mnie naprawdę niepokoi, to to, że nawet po wypróbowaniu wszystkich permutacji lub konfiguracji określonej w specyfikacji na stronie http://docs.angularjs.org/api/ng .directive: select , wciąż dostaję pustą opcję jako pierwsze dziecko elementu select.

Oto Jadeit:

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

Tutaj kontroler:

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

Na koniec generowany jest kod 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>

Co muszę zrobić, aby się go pozbyć?

PS: Bez tego wszystko działa, ale wygląda dziwnie, jeśli używasz select2 bez wielokrotnego wyboru.

Sudhanshu
źródło

Odpowiedzi:

646

Puste optionjest generowane, gdy wartość, do której odwołuje się ng-model, nie istnieje w zestawie opcji przekazanych do ng-options. Dzieje się tak, aby zapobiec przypadkowemu wybraniu modelu: AngularJS widzi, że model początkowy jest niezdefiniowany lub nie znajduje się w zestawie opcji i nie chce samodzielnie decydować o wartości modelu.

Jeśli chcesz pozbyć się pustej opcji, po prostu wybierz wartość początkową w kontrolerze, na przykład:

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

Oto jsFiddle: http://jsfiddle.net/MTfRD/3/

Krótko mówiąc: pusta opcja oznacza, że ​​nie został wybrany żaden prawidłowy model (przez prawidłowy mam na myśli: z zestawu opcji). Musisz wybrać prawidłową wartość modelu, aby pozbyć się tej pustej opcji.

pkozlowski.opensource
źródło
7
Próbowałem z obu $ scope.form.type = ''; i $ scope.form.type = $ scope.typeOptions [0], jednak nadal widzę to - <wartość opcji = "?" selected = "selected"> </option>
Sudhanshu
5
Czasami naprawdę nie ma sensu mieć tych danych w JS. Jeśli to serwer podjął decyzję o tym, co było w tym wyborze, dlaczego JS miałoby to powielić?
heneryville,
11
To niestety nie działa, jeśli używasz tablicy i nulljest jedną z twoich wartości.
vpiTriumph,
6
Czy można dodać tekst do pustego, <option>więc wygenerowano kątowo tat - coś takiego<option value="?">Select an option</option>
RPDeshaies
3
@ Tareck117 tylko wirte <option value="">Select an option</option>thats null-Value z list opcji. Nie potrzeba znaku?
Sebastian
235

Jeśli chcesz uzyskać wartość początkową, zobacz odpowiedź @ pkozlowski.opensource, którą informacje FYI można również zaimplementować w widoku (a nie w kontrolerze) za pomocą 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>

Jeśli nie chcesz wartości początkowej, „pojedynczy element zakodowany na stałe, z wartością ustawioną na pusty ciąg znaków, może być zagnieżdżony w elemencie. Ten element będzie wówczas reprezentował opcję zerową lub opcję„ nie wybrano ”:

<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
źródło
4
@hugo, działające skrzypce: jsfiddle.net/4qKyx/1 Zauważ, że pokazane jest „wybierz typ”, ale nie ma z nim żadnej wartości. A kiedy wybierzesz coś innego, nie zobaczysz go ponownie. (Test na Chrome.)
Mark Rajcok
1
@MarkRajcok - doskonała sugestia! natknąłem się na inną kwestię, korzystając z twojego przykładu z wytłumaczeniem dyrektywy. Czy mógłbyś spojrzeć? plnkr.co/edit/efaZdEQlNfoDihk1R1zc?p=preview
Jan-Terje Sørensen
2
Problem w tym, że nadal możesz wybierać za pomocą klawiatury, patrz stackoverflow.com/a/8442831/57344 rozwiązanie
HaveAGuess
2
Może to na razie działać, ale dokumentacja kątowa wyraźnie odradza
Ed Norris
3
Nie działa w IE10, „wybierz typ” jest zawsze widoczny i możliwy do wyboru.
Robin
121

Kątowy <1,4

Dla każdego, kto traktuje „null” jako prawidłową wartość jednej z opcji (wyobraź sobie, że „null” jest wartością jednego z elementów w typeOptions w poniższym przykładzie), znalazłem ten najprostszy sposób, aby upewnić się, że automatycznie dodaje się opcja jest ukryta to użyć ng-if.

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

Dlaczego ng-if, a nie ng-hide? Ponieważ chcesz, aby selektory css były kierowane na pierwszą opcję powyżej, wybierz opcję „rzeczywistą”, a nie tę ukrytą. Przydaje się, gdy używasz kątomierza do testowania e2e i (z jakiegokolwiek powodu) używasz by.css (), aby celować w wybrane opcje.

Kątowe> = 1,4

Ze względu na refaktoryzację dyrektyw select i options używanie ng-ifnie jest już realną opcją, więc musisz się zwrócić, aby ng-show="false"znów działać.

WTK
źródło
5
Powinna być zaakceptowana odpowiedź, ponieważ jest to prawidłowe zachowanie wizualne dla wybranych. Umieszczasz size="5"atrybuty selekcji i widzisz, że nic nie zostało wybrane! Jak w domyślnym <select>elemencie! Nie rozumiem, dlaczego angular robi takie rzeczy dla selekcji bez multipleatrybutu ...
Sebastian
1
Tak, zgadzam się, to powinna być zaakceptowana odpowiedź. To jest „droga kątowa”. ng-if faktycznie usuwa element opcji z domeny (gdy false), więc to rozwiązanie działa również we wszystkich przeglądarkach bez kodowania „hacky” (w przeciwieństwie do ng-hide lub ng-show).
Sander_P
2
@Sander_P z definicji to rozwiązanie jest według mnie „hacky” (wkładanie czegoś w dom, aby podstępem podważyć jego usunięcie), ale masz rację, nadal jest to „najlepsze” rozwiązanie. „Jeszcze lepszym” rozwiązaniem byłoby wybranie cholernego wyboru, który nie ma żadnej wartości! Co za cholera? To nie tak, że jest to skrajny scenariusz.
dudewad
@dudewad: z Angular 1.4 może działać lepiej. Z bloga AngularJS dla wersji 1.4.0: „ngOptions zostało całkowicie przebudowane, aby umożliwić naprawienie wielu irytujących błędów”
Sander_P
1
Haha „irytujące błędy”. W porządku. Cóż, wciąż jestem trochę niedorzeczny, jeśli chodzi o aktualizację na 3 dni przed dostawą, więc na razie będę trzymać twoje rozwiązanie, które wydaje się działać płynnie. Znane na przyszłość :) Dzięki!
dudewad
36

Może przydatne dla kogoś:

Jeśli chcesz użyć zwykłych opcji zamiast opcji ng, możesz zrobić to tak:

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

Ustaw model w linii. Użyj ng-init, aby pozbyć się pustej opcji

Abraham Jagadeesh
źródło
Nie byłem w stanie znaleźć wyraźnego przykładu konfigurowania opcji ng za pomocą obiektów OBJECTS, a nie tablic JSON, a kiedy próbuję „tłumaczyć” między nimi, nie tylko nie wychodzi to dobrze, ale kończy się „cicho”, więc Nie mam pojęcia, co robię źle. W końcu zdecydowałem się na zwykłe powtórzenie ng w tagu opcji. Wiem, że to nie jest najlepsza praktyka, ale przynajmniej DZIAŁA. Jeśli ktokolwiek może wskazać mi prosty, łatwy do zamiany na szczegóły, przyjazny dla kąta n00b przykład PRACY przy użyciu opcji ng z obiektami danych (NIE JSON), byłbym podekscytowany. Podwójnie zadowolony, jeśli używa również ng-init.
code-sushi
Używam prostych opcji, ale wydaje się, że w kontrolerze nie otrzymuję wartości wybranej listy rozwijanej. Np .: Próbowałem alert ($ scope.sortorder.value); i alert ($ scope.sortorder); oba dają niezdefiniowane. Jak uzyskać wybraną wartość tutaj?
Maverick Riz
Dziękuję bardzo za to. Właśnie miałem napisać w kontrolerze zupełnie bezużyteczny obiekt, którego nie potrzebowałem. Potrzebowałem tylko prostego wyboru. Jeszcze raz dziękuję.
Muhammad bin Yusrat
22

Przydarzyło mi się coś podobnego i było spowodowane aktualizacją do wersji kątowej 1.5. ng-initwygląda na to, że jest analizowany pod kątem typu w nowszych wersjach Angulara. W starszych Angular ng-init="myModelName=600"odwzorowałby na opcję o wartości „600”, tj. <option value="600">First</option>Ale w Angular 1.5 nie znalazłby tego, ponieważ wydaje się, że spodziewa się znaleźć opcję o wartości 600 tj <option value=600>First</option>. Angular wstawiłby następnie losowy pierwszy element:

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

Kątowy <1.2.x

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

Kątowe> 1,2

<select ng-model="myModelName" ng-init="myModelName='600'">
  <option value="600">First</option>
  <option value="700">Second</option>
</select>
Nabil Boag
źródło
1
Dzięki! W moim przypadku nie mogę użyć ng-init (bez wartości domyślnej), więc rzuciłem mój model na ciąg i zadziałało!
Rodrigo Graça
Bardzo przydatne do mojego problemu z produkcją aplikacji. Dzięki @Nabil Boag
Venki
3
To działa, na pewno, ale lepsze rozwiązania jest użycie ng-value="600"w optionzamiast value. Przetwarza to na liczbę i nie musisz konwertować swoich wartości tak jak teraz :)
Max
@Max Próbowałem wielu cennych odpowiedzi, ale żadne nie działało, dopóki nie znalazłem twojego. Dziękuję Ci.
Andrew
21

Wśród mnóstwa odpowiedzi tutaj, pomyślałem, że opublikuję rozwiązanie, które dla mnie zadziałało i spełniło wszystkie następujące warunki:

  • podał symbol zastępczy / monit, gdy model ng jest fałszem (np. „--select region--” w. value="")
  • gdy wartość modelu ng jest fałszem, a użytkownik otwiera menu rozwijane opcje, wybierany jest symbol zastępczy (inne wymienione tu rozwiązania powodują, że pierwsza opcja wydaje się wybrana, co może wprowadzać w błąd)
  • pozwala użytkownikowi odznaczyć prawidłową wartość, zasadniczo ponownie wybierając wartość fałsz / wartość domyślna

wprowadź opis zdjęcia tutaj

kod

<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

oryginalne pytania i odpowiedzi - https://stackoverflow.com/a/32880941/1121919

jusopi
źródło
Masz na myśli, jeśli domyślnie jest <option ng-selected="true" value="null">?
jusopi,
Mam na myśli to, że jeśli wartość modelu ng jest ustawiona na zero, kątowe tworzy i opróżnia opcję zaznaczenia
Flezcano
16

Szybkie rozwiązanie:

select option:empty { display:none }

Mam nadzieję, że to komuś pomoże. Idealnie, wybraną odpowiedzią powinno być podejście, ale jeśli to nie jest możliwe, powinno działać jako łatka.

KK
źródło
2
Zgodnie z moimi testami będzie to działać tylko w Chrome (na dodatek nowy Chrome) i Firefox. Przerwa w IE i Safari. Nie wiem o operze i innych przeglądarkach krawędzi. Tak czy inaczej, nie jest to niestety dobre rozwiązanie.
dudewad
gdzie powinniśmy umieścić to w html przed zamknięciem <select> lub w js
H Varma
1
@HVarma To reguła CSS. Umieść go w arkuszu stylów lub w znaczniku <style>
KK
@KK stackoverflow.com/questions/48355599/... Czy możesz to sprawdzić?
Sudarshan Kalebere
14

Tak ng-model utworzy pustą wartość opcji, gdy właściwość ng-model będzie niezdefiniowana. Możemy tego uniknąć, przypisując obiekt do modelu ng

Przykład

kodowanie kątowe

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

Ważna uwaga:

Przypisz obiekt tablicy, taki jak $ scope.collections [0] lub $ scope.collections [1] do ng-model, nie używaj właściwości obiektu. jeśli otrzymujesz wartość opcji z serwera, używając funkcji oddzwaniania, przypisz obiekt do modelu ng

UWAGA z dokumentu kątowego

Uwaga: ngModel porównuje przez odniesienie, a nie wartość. Jest to ważne przy wiązaniu z tablicą obiektów. patrz przykład http://jsfiddle.net/qWzTb/

próbowałem wiele razy, w końcu to znalazłem.

Kanagaraj Vadivel
źródło
8

Chociaż odpowiedzi zarówno @ pkozlowski.opensource, jak i @ Mark są poprawne, chciałbym udostępnić moją nieco zmodyfikowaną wersję, w której zawsze wybieram pierwszy element na liście, niezależnie od jego wartości:

<select ng-options="option.value as option.name for option in typeOptions" ng-init="form.type=typeOptions[0].value">
</select>
denkan
źródło
4

Korzystam z Angulara 1.4x i znalazłem ten przykład, więc użyłem ng-init, aby ustawić wartość początkową w select:

<select ng-init="foo = foo || items[0]" ng-model="foo" ng-options="item as item.id for item in items"></select>
James Drinkard
źródło
3


Napotkałem ten sam problem. Jeśli publikujesz formularz kątowy z normalnym postem, napotkasz ten problem, ponieważ kątowy nie pozwala na ustawienie wartości opcji w sposób, w jaki użyłeś. Jeśli otrzymasz wartość „form.type”, znajdziesz odpowiednią wartość. Musisz zaksięgować obiekt kątowy, który nie jest formalnym słupkiem.

Jitu
źródło
3

Prostym rozwiązaniem jest ustawienie opcji z pustą wartością. ""Znalazłem, że eliminuje to dodatkową niezdefiniowaną opcję.

kgrondell
źródło
5
Doenst work @ 1.4.3, Po prostu dodaje 2 puste opcje do formularza
Denny Mueller
3

Ok, właściwie odpowiedź jest bardzo prosta: gdy istnieje opcja nie rozpoznana przez Angulara, obejmuje ona nudną. To, co robisz źle, to to, że kiedy używasz opcji ng, to czyta obiekt, powiedzmy[{ id: 10, name: test }, { id: 11, name: test2 }] right?

To właśnie musi być wartość twojego modelu, aby ocenić ją jako równą, powiedz, że chcesz, aby wybrana wartość wynosiła 10, musisz ustawić swój model na wartość podobną { id: 10, name: test }do wybrania 10, dlatego NIE utworzy tego kosza.

Mam nadzieję, że to pomaga wszystkim zrozumieć, miałem trudny czas próbując :)

Marco
źródło
2

To rozwiązanie działa dla mnie:

<select ng-model="mymodel">    
   <option ng-value="''" style="display:none;" selected>Country</option>
   <option value="US">USA</option>
</select>
MMM
źródło
Downvote może wynikać z tego, że zastosowanie CSS do elementów opcji nie działa we wszystkich przeglądarkach.
Kafoso,
Właśnie przetestowałem to na Chrome, FireFox, Safari i Edge - wszystko działa.
MMM,
@MMM „wszystkie przeglądarki” obejmują IE. Wielu użytkowników wciąż utknęło w IE 10 i 11, i prawdopodobnie dlatego nastąpiło negatywne zdanie. Chrome, fF, Saf i Edge nie są „wszystkimi przeglądarkami”.
PKD
1

To zadziałało dla mnie

<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
źródło
Po prostu dodaje opcję do listy i niestety pozostawia puste miejsce.
AMontpetit
1

Działa to doskonale

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

działa to tak, że daje to pierwszą opcję do wyświetlenia przed wybraniem czegoś i display:noneusuwa to z listy rozwijanej, więc jeśli chcesz, możesz to zrobić

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

a to da ci select and optionprzed wyborem, ale po wybraniu zniknie i nie pojawi się w menu rozwijanym.

David Genger
źródło
W rzeczywistości nie odpowiadasz na pytanie, co najgorsze, po prostu ukrywasz element.
Marco
0

Wypróbuj ten w swoim kontrolerze, w tej samej kolejności:

$scope.typeOptions = [
    { name: 'Feature', value: 'feature' }, 
    { name: 'Bug', value: 'bug' }, 
    { name: 'Enhancement', value: 'enhancement' }
];
$scope.form.type = $scope.typeOptions[0];
Macfer Ann
źródło
Próbowałem twojej metody, ale niestety nie udało mi się jej uruchomić. Czy możesz rzucić okiem na to skrzypce? jsfiddle.net/5PdaX
Sinha
0

Oto poprawka:

dla przykładowych danych, takich jak:

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

Wybierz opcję powinna wyglądać tak: -

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

Chodzi o to, że kiedy piszemy value.listCountjako value.listName, automatycznie wypełnia tekst, value.listNameale wartość wybranej opcji tovalue.listCount chociaż wartości moje pokazują normalne 0,1,2 .. i tak dalej !!!

W moim przypadku financeRef.financeLimitfaktycznie chwytam value.listCounti mogę dynamicznie manipulować w kontrolerze.

lisapanda
źródło
0

Chciałbym dodać, że jeśli wartość początkowa pochodzi z powiązania z jakiegoś elementu nadrzędnego lub komponentu 1.5, upewnij się, że przekazano odpowiedni typ. Jeśli używasz @w powiązaniu, przekazywana zmienna będzie ciągiem znaków, a jeśli opcjami są np. liczby całkowite, pojawi się pusta opcja.

Albo poprawnie parsuj wartość w init, albo powiązaj zi <nie @(mniej zalecane dla wydajności, jeśli nie jest to konieczne).

Wtower
źródło
0

Proste rozwiązanie

<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
źródło
0

Grind rozwiązanie z jQuery, gdy nie masz kontroli nad opcjami

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
źródło
Pascal, ktoś cię ocenił, ponieważ jest to rozwiązanie jQuery, a nie AngularJs
Mawg mówi o przywróceniu Moniki
Zadaje się pytanie, aby dowiedzieć się więcej o Angular ...: - /
Sahu V Kumar
0

Jeśli używasz ng-init swojego modelu do rozwiązania tego problemu:

<select ng-model="foo" ng-app ng-init="foo='2'">
Pauly Garcia
źródło
0

miałem ten sam problem, ja (usunąłem „ng-model”) zmieniłem to:

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

do tego:

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

teraz działa, ale w moim przypadku było to spowodowane tym, że usunąłem ten zakres z ng.controller, sprawdź, czy nie zrobiłeś tego samego.

Kuza Grave
źródło
0

Jedyną rzeczą, pracował dla mnie jest użycie track byw ng-optionsnastępujący sposób:

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

Dipendu Paul
źródło
jeśli mogę użyć tego ng-optiondostać ostatnią wartość tablicy, która chcę ustalonej wartości optionz select. Nie udało się rozwiązać :(
rufatZZ
0

Zobacz przykład z dokumentacji angularjs, jak przezwyciężyć te problemy.

  1. Przejdź do linku do dokumentacji tutaj
  2. Znajdź „ Powiązanie zaznaczenia do wartości nieciągowej poprzez parsowanie / formatowanie ngModel
  3. Widzisz tam, dyrektywa o nazwie „ convertToNumber ” rozwiązuje problem.

Mi to pasuje. Można również zobaczyć, jak to działa tutaj

ihsanberahim
źródło
0

Możemy użyć CSS, aby ukryć pierwszą opcję, ale to nie zadziała w IE 10, 11. Najlepszym sposobem jest usunięcie elementu za pomocą Jquery. To rozwiązanie działa w przypadku głównych przeglądarek testowanych w Chrome i IE10, 11

Również jeśli używasz kątowego, czasami używa setTimeout

$scope.RemoveFirstOptionElement = function (element) {
    setTimeout(function () {
        $(element.children()[0]).remove();
    }, 0);
};
Ashok Kumar
źródło