Praca z select przy użyciu opcji ng AngularJS


442

Czytałem o tym w innych postach, ale nie mogłem tego rozgryźć.

Mam tablicę,

$scope.items = [
   {ID: '000001', Title: 'Chicago'},
   {ID: '000002', Title: 'New York'},
   {ID: '000003', Title: 'Washington'},
];

Chcę to wyrenderować jako:

<select>
  <option value="000001">Chicago</option>
  <option value="000002">New York</option>
  <option value="000003">Washington</option>
</select>

A także chcę wybrać opcję o ID = 000002.

Czytałem select i próbował, ale nie mogę zrozumieć.


Bardzo polecam korzystanie z Select2 , ponieważ poradzi sobie z tym za Ciebie. Istnieje nawet dyrektywa dla AngularJS .
— hewstone


W rzeczywistości istnieje rozwiązanie AngularJS opracowane przez QuantumUI . Więcej przykładów i dokumentacji można znaleźć na stronie http://quantumui.org/ .
— Ramon Drunce,

Odpowiedzi:


799

Należy zauważyć, że ngModel jest wymagany do działania ngOptions ... zwróć uwagę nang-model="blah" to, że „ustaw $ scope.blah na wybraną wartość”.

Spróbuj tego:

<select ng-model="blah" ng-options="item.ID as item.Title for item in items"></select>

Oto więcej z dokumentacji AngularJS (jeśli jeszcze go nie widziałeś):

dla źródeł danych tablicowych:

  • etykieta wartości w tablicy
  • wybierz jako etykietę wartości w tablicy
  • etykieta grupa po grupie dla wartości w tablicy = wybierz jako etykieta grupa po grupie dla wartości w tablicy

dla źródeł danych obiektowych:

  • etykieta dla (klucz, wartość) w obiekcie
  • wybierz jako etykietę dla (klucz, wartość) w obiekcie
  • etykieta grupa po grupie dla (klucz, wartość) w obiekcie
  • wybierz jako grupę etykiet po grupie dla (klucz, wartość) w obiekcie

W celu wyjaśnienia wartości tagów opcji w AngularJS:

Gdy używasz ng-options, wartości tagów opcji wypisanych przez ng-options zawsze będą indeksem elementu tablicy, do którego odnosi się tag opcji . Wynika to z faktu, że AngularJS pozwala na zaznaczanie całych obiektów za pomocą kontrolek wyboru, a nie tylko typów pierwotnych. Na przykład:

app.controller('MainCtrl', function($scope) {
   $scope.items = [
     { id: 1, name: 'foo' },
     { id: 2, name: 'bar' },
     { id: 3, name: 'blah' }
   ];
});
<div ng-controller="MainCtrl">
   <select ng-model="selectedItem" ng-options="item as item.name for item in items"></select>
   <pre>{{selectedItem | json}}</pre>
</div>

Powyższe pozwoli ci wybrać $scope.selectedItembezpośrednio cały obiekt . Chodzi o to, że dzięki AngularJS nie musisz się martwić o to, co jest w tagu opcji. Niech AngularJS sobie z tym poradzi; powinieneś dbać tylko o to, co jest w twoim modelu w twoim zakresie.

Oto plunker demonstrujący powyższe zachowanie i pokazujący napisany HTML


Postępowanie z opcją domyślną:

Jest kilka rzeczy, o których nie wspomniałem powyżej, odnoszących się do opcji domyślnej.

Wybieranie pierwszej opcji i usuwanie pustej opcji:

Możesz to zrobić, dodając prosty element, ng-initktóry ustawia model (od ng-model) do pierwszego elementu w elementach, w których się powtarzasz ng-options:

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

Uwaga: Może to być trochę szalone, jeśli foozdarzy się, że zostanie poprawnie zainicjowane na coś „falsy”. W takim przypadku będziesz chciał obsłużyć inicjalizacjęfoo najprawdopodobniej w kontrolerze.

Dostosowywanie opcji domyślnej:

To jest trochę inne; tutaj wszystko, co musisz zrobić, to dodać tag opcji jako wybrany element podrzędny z pustym atrybutem wartości, a następnie dostosować jego tekst wewnętrzny:

<select ng-model="foo" ng-options="item as item.name for item in items">
   <option value="">Nothing selected</option>
</select>

Uwaga: w tym przypadku opcja „pusta” pozostanie tam nawet po wybraniu innej opcji. Nie dotyczy to domyślnego zachowania selekcji w AngularJS.

Dostosowana domyślna opcja, która ukrywa się po dokonaniu wyboru:

Jeśli chcesz, aby niestandardowa opcja domyślna zniknęła po wybraniu wartości, możesz dodać atrybut ng-hide do opcji domyślnej:

<select ng-model="foo" ng-options="item as item.name for item in items">
   <option value="" ng-if="foo">Select something to remove me.</option>
</select>

3
Okazuje się, że są to wskaźniki wartości, w ten sposób kąt pozwala na użycie obiektów jako wartości twojego pola wyboru. Angular robi dla ciebie wiele rzeczy za kulisami z wybranymi polami i nie powinieneś się martwić atrybutem wartości opcji.
— Ben Lesh,

1
Dokumentacja znajduje się pod „select” na swojej stronie: docs.quarejs.org/api/ng.directive:select
— Ben Lesh

25
„... ngModel jest wymagany do działania ngOptions ...” był dla mnie sednem problemu. Dobra odpowiedź.
— tristanm

1
Czy można uniknąć pierwszej pustej opcji ( <option value="?" selected="selected"></option>)?
— swenedo

4
Próbuję użyć ostatniego przypadku ( niestandardowa domyślna opcja, która ukrywa się po dokonaniu wyboru ), ale znalazłem pewne problemy. Zamiast ng-if="foo"musiałem użyć, ng-if=!fooaby ukryć domyślną pustą opcję, gdy wybrana jest inna opcja. Ponadto domyślna pusta opcja pojawia się zawsze na dole listy kombinacji. Jak mogę umieścić to na początku listy kombinacji?
— Fran Herrero,

90

Uczę się AngularJS i również zmagałem się z wyborem. Wiem, że na to pytanie już udzielono odpowiedzi, ale mimo to chciałem udostępnić trochę więcej kodu.

W moim teście mam dwie listy: marki samochodów i modele samochodów. Lista modeli jest wyłączona, dopóki nie zostanie wybrana marka. Jeśli wybór w powoduje, że pole listy zostanie później zresetowane (ustawione na „Wybierz markę”), wówczas pole listy modeli zostanie ponownie wyłączone ORAZ jego wybór również zostanie zresetowany (do „Wybierz model”). Sprawia, że ​​są pobierane jako zasób, podczas gdy modele są po prostu zakodowane na stałe.

Sprawia, że ​​JSON:

[
{"code": "0", "name": "Select Make"},
{"code": "1", "name": "Acura"},
{"code": "2", "name": "Audi"}
]

services.js:

angular.module('makeServices', ['ngResource']).
factory('Make', function($resource){
    return $resource('makes.json', {}, {
        query: {method:'GET', isArray:true}
    });
});

Plik HTML:

<div ng:controller="MakeModelCtrl">
  <div>Make</div>
  <select id="makeListBox"
      ng-model="make.selected"
      ng-options="make.code as make.name for make in makes"
      ng-change="makeChanged(make.selected)">
  </select>

  <div>Model</div>
  <select id="modelListBox"
     ng-disabled="makeNotSelected"
     ng-model="model.selected"
     ng-options="model.code as model.name for model in models">
  </select>
</div>

kontrolery.js:

function MakeModelCtrl($scope)
{
    $scope.makeNotSelected = true;
    $scope.make = {selected: "0"};
    $scope.makes = Make.query({}, function (makes) {
         $scope.make = {selected: makes[0].code};
    });

    $scope.makeChanged = function(selectedMakeCode) {
        $scope.makeNotSelected = !selectedMakeCode;
        if ($scope.makeNotSelected)
        {
            $scope.model = {selected: "0"};
        }
    };

    $scope.models = [
      {code:"0", name:"Select Model"},
      {code:"1", name:"Model1"},
      {code:"2", name:"Model2"}
    ];
    $scope.model = {selected: "0"};
}

27
Drogi losowy użytkowniku. Chociaż to pytanie i jego odpowiedź są raczej proste i nieskomplikowane, twoja organizacja kodu w odpowiednie i odpowiednie lokalizacje (kontroler, usługa, szablon, dane) pokazuje elegancję AngularJS w jego najprostszej i domyślnej formie. Świetny przykład.
— Atticus

1
Nie tak powinno się go używać. ng-modelpowinien wskazywać inną zmienną w twoim zakresie, niezwiązaną z make. Zobacz przykład w docs.quarejs.org/api/ng/directive/ngOptions
— Dmitri Zaitsev

@DmitriZaitsev Myślę, że się mylisz, tylko dlatego, że przykład kątowego dokumentu pokazuje to tak, jak opisałeś, nie oznacza, że ​​to jedyny sposób. Pokaż nam, dlaczego uważasz, że nie powinno się go używać w ten sposób, zamiast marnować świetny przykład dla początkujących.
— JRT

39

Z jakiegoś powodu AngularJS pozwala mi się pomylić. Ich dokumentacja jest w tym dość okropna. Przydałoby się więcej dobrych przykładów odmian.

W każdym razie mam niewielkie różnice w odpowiedzi Bena Lesha.

Moje kolekcje danych wyglądają następująco:

items =
[
   { key:"AD",value:"Andorra" }
,  { key:"AI",value:"Anguilla" }
,  { key:"AO",value:"Angola" }
 ...etc..
]

Teraz

<select ng-model="countries" ng-options="item.key as item.value for item in items"></select>

nadal powodowało, że wartością opcji był indeks (0, 1, 2 itd.).

Dodanie utworu Naprawiono to dla mnie:

<select ng-model="blah" ng-options="item.value for item in items track by item.key"></select>

Wydaje mi się, że częściej zdarza się, że chcesz dodać tablicę obiektów do listy wyboru, więc zapamiętam ten!

Pamiętaj, że z AngularJS 1.4 nie możesz już używać opcji ng, ale musisz użyć ng-repeattagu opcji:

<select name="test">
   <option ng-repeat="item in items" value="{{item.key}}">{{item.value}}</option>
</select>

3
Ta odpowiedź wydaje się być dokładnie tym, o co pyta pytanie. Każda inna odpowiedź mówi czytelnikowi, aby nie martwił się o generowany HTML, ale jeśli element select jest w formie, bardzo się martwię. Świetna odpowiedź!
— Keith

3
Należy zauważyć, że przechowuje to w pełni wybrany obiekt w modelu, a nie tylko klucz. Jeśli chcesz tylko klucz w modelu, chcesz użyć wersji „item.key jako item.value”. Przez pewien czas byłem tym zdezorientowany, ponieważ odłożyłem słuchawkę, jak wyglądał HTML, a nie dane, które chciałem w modelu, co jest dla mnie najważniejsze.
— mhenry1384

@ mhenry1384 Tak, masz rację, jeśli chodzi o przechowywanie całego obiektu. Naprawdę podoba mi się ta funkcja, ponieważ daje dostęp do więcej niż tylko identyfikatora (jeśli jest to potrzebne). Działa dla mnie dobrze, gdy zapełniam listy kolekcją mongo i potrzebuję trochę właściwości z wybranego elementu.
— Mattijs

2
I jak możemy wykryć zmiany z „ng-zmianą” w środku option?
— Konstantinos Natsios

2
Jeśli chodzi o aktualizację, nie wygląda to dobrze. Opcje ng nadal działają poprawnie w wersji 1.5. Jest to nadal widoczne w dokumentacji. docs.quarejs.org/api/ng/directive/select
— Jeremy A. West

15

Odpowiedź na pytanie jest już udzielona (BTW, naprawdę dobra i wyczerpująca odpowiedź udzielona przez Bena), ale chciałbym dodać kolejny element kompletności, który może być również bardzo przydatny.

W przykładzie zasugerowanym przez Bena:

<select ng-model="blah" ng-options="item.ID as item.Title for item in items"></select>

wymienionym poniżej ngOptions forma została wykorzystana: select as label for value in array.

Etykieta jest wyrażeniem, którego wynikiem będzie etykieta<option> elementu. W takim przypadku możesz wykonać określone konkatenacje ciągów, aby uzyskać bardziej złożone etykiety opcji.

Przykłady:

  • ng-options="item.ID as item.Title + ' - ' + item.ID for item in items" daje etykiety jak Title - ID
  • ng-options="item.ID as item.Title + ' (' + item.Title.length + ')' for item in items"daje etykiety takie jak Title (X), gdzie Xjest długość ciągu tytułu.

Możesz także użyć filtrów, na przykład

  • ng-options="item.ID as item.Title + ' (' + (item.Title | uppercase) + ')' for item in items" daje etykiety jak Title (TITLE) , gdzie wartość tytułu właściwości tytułu i TYTUŁU jest taka sama, ale jest konwertowana na wielkie litery.
  • ng-options="item.ID as item.Title + ' (' + (item.SomeDate | date) + ')' for item in items"daje etykiety, np. Title (27 Sep 2015)jeśli twój model ma właściwośćSomeDate

7

W CoffeeScript:

#directive
app.directive('select2', ->
    templateUrl: 'partials/select.html'
    restrict: 'E'
    transclude: 1
    replace: 1
    scope:
        options: '='
        model: '='
    link: (scope, el, atr)->
        el.bind 'change', ->
            console.log this.value
            scope.model = parseInt(this.value)
            console.log scope
            scope.$apply()
)
<!-- HTML partial -->
<select>
  <option ng-repeat='o in options'
          value='{{$index}}' ng-bind='o'></option>
</select>

<!-- HTML usage -->
<select2 options='mnuOffline' model='offlinePage.toggle' ></select2>

<!-- Conclusion -->
<p>Sometimes it's much easier to create your own directive...</p>

1
Nie zapomnij radixo parseInt: http://davidwalsh.name/parseint-radix
— GFoley83

6

Jeśli potrzebujesz niestandardowego tytułu dla każdej opcji, ng-optionsnie dotyczy. Zamiast tego użyj ng-repeatz opcjami:

<select ng-model="myVariable">
  <option ng-repeat="item in items"
          value="{{item.ID}}"
          title="Custom title: {{item.Title}} [{{item.ID}}]">
       {{item.Title}}
  </option>
</select>

3

Mam nadzieję, że następujące działania będą dla Ciebie działać.

<select class="form-control"
        ng-model="selectedOption"
        ng-options="option.name + ' (' + (option.price | currency:'USD$') + ')' for option in options">
</select>

1

To może być przydatne. Wiązania nie zawsze działają.

<select id="product" class="form-control" name="product" required
        ng-model="issue.productId"
        ng-change="getProductVersions()"
        ng-options="p.id as p.shortName for p in products"></select>

Na przykład wypełniasz model źródłowy listy opcji z usługi REST. Wybrana wartość była znana przed wypełnieniem listy i została ustawiona. Po wykonaniu żądania REST za pomocą $ http opcja listy jest wykonywana.

Ale wybrana opcja nie jest ustawiona. Z nieznanych powodów wykonanie AngularJS w cieniu $ digest nie wiąże wybranego tak, jak powinno. Muszę użyć jQuery, aby ustawić wybrane. To ważne! AngularJS, w cieniu, dodaje przedrostek do wartości „wartości” attr dla opcji generowanych przez ng-repeat. Dla int jest to „liczba:”.

$scope.issue.productId = productId;
function activate() {
    $http.get('/product/list')
       .then(function (response) {
           $scope.products = response.data;

           if (productId) {
               console.log("" + $("#product option").length);//for clarity
               $timeout(function () {
                   console.log("" + $("#product option").length);//for clarity
                   $('#product').val('number:'+productId);

               }, 200);
           }
       });
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.