Lucrul cu select folosind ng-options din AngularJS (Programare, Javascript, Angularjs, Html Select, Opțiuni Ng)

Andrej Kaurin a intrebat.

Am citit despre asta în alte postări, dar nu am reușit să înțeleg.

Am o matrice,

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

Vreau să o redau ca:

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

Și, de asemenea, vreau să selectez opțiunea cu ID=000002.

Am citit select și am încercat, dar nu reușesc să înțeleg.

Comentarii

8 răspunsuri
Ben Lesh

Un lucru de reținut este că ngModel este necesar pentru ca ngOptions să funcționeze… rețineți că ng-model="blah" care spune „setați $scope.blah la valoarea selectată”.

Încercați acest lucru:

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

Iată mai multe informații din documentația AngularJS (dacă nu ați văzut-o):

pentru surse de date de tip array:

  • etichetă pentru valoarea din matrice
  • selectați ca etichetă pentru valoarea din matrice
  • label group by group for value in array = select as label group by group for group for value in array

pentru sursele de date obiect:

  • etichetă pentru (cheie , valoare) în obiect
  • select as label for (key , value) în object
  • label group by group for (key, value) in object
  • select as label group by group for (key, value) in object: select as label group by group for (key, value) in object

Pentru câteva clarificări privind valorile etichetelor de opțiune în AngularJS:

Atunci când utilizați ng-options, valorile etichetelor de opțiune scrise de ng-options vor fi întotdeauna indexul elementului din matrice la care se referă eticheta de opțiune.. Acest lucru se datorează faptului că AngularJS vă permite de fapt să selectați obiecte întregi cu ajutorul controalelor de selectare, și nu doar tipuri primitive. De exemplu:

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>

Textul de mai sus vă va permite să selectați un obiect întreg în $scope.selectedItem în mod direct. Ideea este că, cu AngularJS, nu trebuie să vă faceți griji cu privire la ceea ce se află în tag-ul option. Lăsați-l pe AngularJS să se ocupe de asta; ar trebui să vă intereseze doar ceea ce se află în modelul dvs. în domeniul dvs. de aplicare.

Iată un plunker care demonstrează comportamentul de mai sus și care arată HTML-ul scris


Gestionarea opțiunii implicite:

Există câteva lucruri pe care am omis să le menționez mai sus în legătură cu opțiunea implicită.

Selectarea primei opțiuni și eliminarea opțiunii goale:

Puteți face acest lucru adăugând un simplu ng-init care stabilește modelul (de la ng-model) la primul element din elementele pe care le repetați în ng-options:

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

Notă: Acest lucru ar putea deveni un pic nebunesc dacă foo se întâmplă să fie inițializat în mod corespunzător la ceva „fals”. În acest caz, veți dori să vă ocupați de inițializarea lui foo în controlerul tău, cel mai probabil.

Personalizarea opțiunii implicite:

Acest lucru este puțin diferit; aici tot ce trebuie să faceți este să adăugați o etichetă option ca un copil al selectului, cu un atribut value gol, apoi să personalizați textul său interior:

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

Notă: În acest caz, opțiunea „empty” va rămâne acolo chiar și după ce selectați o altă opțiune. Acesta nu este cazul comportamentului implicit al selecturilor în AngularJS.

O opțiune implicită personalizată care se ascunde după ce se face o selecție:

Dacă ați dorit ca opțiunea implicită personalizată să dispară după ce selectați o valoare, puteți adăuga un atribut ng-hide la opțiunea implicită:

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

Comentarii

  • Se pare că aceștia sunt indicii valorilor, acesta este modul în care Angular vă poate permite să utilizați obiecte ca valoare a casetei de selectare. Angular face o mulțime de lucruri pentru tine în spatele scenei cu casetele de selectare, iar tu nu ar trebui să îți faci griji cu privire la atributul value al opțiunilor tale. –  > Por Ben Lesh.
  • Documentația se găsește la rubrica „select” de pe site-ul lor: docs.angularjs.org/api/ng.directive:select –  > Por Ben Lesh.
  • 25

  • „…ngModel este necesar pentru ca ngOptions să funcționeze…” a fost punctul central al problemei pentru mine. Un răspuns bun. –  > Por tristanm.
  • Este posibil să se evite prima opțiune goală (<option value="?" selected="selected"></option>)? –  > Por swenedo.
  • Încerc să folosesc ultimul caz (O opțiune implicită personalizată care se ascunde după ce se face o selecție), dar am găsit câteva probleme. În loc de ng-if="foo" a trebuit să folosesc ng-if=!foo pentru a ascunde opțiunea implicită goală atunci când este selectată o altă opțiune. De asemenea, opțiunea implicită goală apare întotdeauna în partea de jos a listei combinate. Cum aș putea să o pun la începutul listei combinate? –  > Por Fran Herrero.
mp31415

Învăț AngularJS și mă luptam și eu cu selecția. Știu că această întrebare are deja un răspuns, dar am vrut totuși să împărtășesc ceva mai mult cod.

În testul meu am două listbox-uri: mărci de mașini și modele de mașini. Lista de modele este dezactivată până când este selectată o anumită marcă. Dacă selecția în caseta de listă cu mărci este resetată ulterior (setată la „Select Make”), atunci caseta de listă cu modele devine din nou dezactivată ȘI selecția acesteia este resetată și ea (la „Select Model”). Mărcile sunt recuperate ca resursă, în timp ce modelele sunt doar codificate.

Makes 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}
    });
});

Fișier 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>

controllers.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"};
}

Comentarii

    27

  • Dragă utilizator oarecare. În timp ce această întrebare și răspunsul său sunt destul de simple și necomplicate, organizarea codului în locațiile sale corespunzătoare și respective (controler, serviciu, șablon, date) arată eleganța AngularJS în forma sa cea mai simplă și implicită. Un exemplu minunat. –  > Por Atticus.
  • Nu așa ar trebui să fie folosit. ng-model ar trebui să arate spre un alt variabilă din domeniul de aplicare, care nu are legătură cu make. A se vedea exemplul din docs.angularjs.org/api/ng/directive/ngOptions –  > Por Dmitri Zaitsev.
  • @DmitriZaitsev Cred că te înșeli, doar pentru că exemplul din docs angular arată modul în care l-ai descris nu înseamnă că acesta este singurul mod. Arătați-ne de ce credeți că nu ar trebui să fie folosit în acest mod, mai degrabă decât să distrugeți un exemplu excelent pentru începători. –  > Por JRT.
Mattijs

Din anumite motive, AngularJS permite să mă încurce. Documentația lor este destul de oribilă în acest sens. Mai multe exemple bune de variații ar fi binevenite.

Oricum, am o mică variație la răspunsul lui Ben Lesh.

Colecțiile mele de date arată astfel:

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

Acum

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

încă a rezultat că valoarea opțiunilor să fie indicele (0, 1, 2, etc.).

Adăugarea Track By a rezolvat problema pentru mine:

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

Cred că se întâmplă mai des să doriți să adăugați o matrice de obiecte într-o listă de selecție, așa că voi ține minte acest lucru!

Rețineți că începând cu AngularJS 1.4 nu mai puteți folosi ng-options, ci trebuie să folosiți ng-repeat în tag-ul option:

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

Comentarii

  • Acest răspuns pare să fie exact ceea ce cere întrebarea. Orice alt răspuns îi spune cititorului să nu-și facă griji cu privire la ce HTML este generat, dar dacă elementul select este într-un formular, îmi fac foarte multe griji. Un răspuns excelent! –  > Por Keith.
  • Ar trebui subliniat faptul că acest lucru stochează în model întregul obiect selectat, nu doar cheia. Dacă doriți doar cheia în model, trebuie să folosiți versiunea „item.key as item.value”. Acest lucru m-a încurcat pentru o vreme, deoarece eram obsedat de cum arată HTML-ul, nu de datele pe care le doream în model, care, pentru mine, este cel mai important lucru. –  > Por mhenry1384.
  • @mhenry1384 Da, aveți dreptate, în legătură cu stocarea întregului obiect. De fapt, îmi place această caracteristică pentru că îți oferă acces la mai mult decât la ID (dacă ai nevoie.). Funcționează bine pentru mine atunci când populez listele cuo colecție mongo și am nevoie de o anumită proprietate din elementul selectat. –  > Por Mattijs.
  • Și cum putem detecta modificările cu „ng-change” în interiorul „ng-change option ? –  > Por Konstantinos Natsios.
  • În ceea ce privește actualizarea, acest lucru nu pare corect. ng-options încă funcționează bine în 1.5. De asemenea, este încă afișat în documentație. docs.angularjs.org/api/ng/directive/select –  > Por Jeremy A. West.
Tom

Întrebarea a primit deja un răspuns (BTW, un răspuns foarte bun și cuprinzător oferit de Ben), dar aș dori să adaug un alt element pentru completitudine, care poate fi, de asemenea, foarte util.

În exemplul sugerat de Ben:

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

următoarele ngOptions a fost utilizat formularul select as label for value in array.

Etichetă este o expresie, al cărei rezultat va fi eticheta pentru <option> element. În acest caz, puteți efectua anumite concatenări de șiruri de caractere, pentru a obține etichete de opțiuni mai complexe.

Exemple:

  • ng-options="item.ID as item.Title + ' - ' + item.ID for item in items" vă oferă etichete de tipul Title - ID
  • ng-options="item.ID as item.Title + ' (' + item.Title.length + ')' for item in items" vă oferă etichete de tipul Title (X), unde X este lungimea șirului Title.

De asemenea, puteți utiliza filtre, de exemplu,

  • ng-options="item.ID as item.Title + ' (' + (item.Title | uppercase) + ')' for item in items" vă oferă etichete de tipul Title (TITLE), unde valoarea Title a proprietății Title și TITLE este aceeași valoare, dar convertită în caractere majuscule.
  • ng-options="item.ID as item.Title + ' (' + (item.SomeDate | date) + ')' for item in items" vă oferă etichete precum Title (27 Sep 2015), dacă modelul dvs. are o proprietate SomeDate

Akatsuki Sai

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

Comentarii

Dmitri Algazin

Dacă aveți nevoie de un titlu personalizat pentru fiecare opțiune, ng-options nu este aplicabil. În schimb, utilizați ng-repeat cu opțiuni:

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

Meghshyam Sonar

Sper că următoarele vor funcționa pentru dvs.

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

trueboroda

Poate fi util. Legăturile nu funcționează întotdeauna.

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

De exemplu, completați modelul sursă al listei de opțiuni de la un serviciu REST. O valoare selectată era cunoscută înainte de a umple lista și a fost setată. După executarea solicitării REST cu $http, lista de opțiuni este gata.

Dar opțiunea selectată nu este setată. Din motive necunoscute, AngularJS în umbră $digest executând nu leagă selectat așa cum ar trebui să fie. Trebuie să folosesc jQuery pentru a seta selectat. Este important! AngularJS, în umbră, adaugă prefixul la valoarea attr-ului „value” pentru opțiunile generate de ng-repeat. Pentru int este „number:”.

$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);
           }
       });
}