Arbeiten mit select mithilfe der ng-Optionen von AngularJS

442

Ich habe darüber in anderen Posts gelesen, konnte es aber nicht herausfinden.

Ich habe ein Array,

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

Ich möchte es rendern als:

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

Außerdem möchte ich die Option mit ID = 000002 auswählen.

Ich habe select gelesen und versucht, aber ich kann es nicht herausfinden.

Andrej Kaurin
quelle
Ich empfehle die Verwendung von Select2 , da dies für Sie erledigt wird. Es gibt sogar eine Richtlinie für AngularJS .
Hewstone
Tatsächlich gibt es eine reine AngularJS-Lösung, die von QuantumUI entwickelt wurde . Weitere Beispiele und Dokumentationen finden Sie unter http://quantumui.org/ .
Ramon Drunce

Antworten:

799

Eine Sache zu beachten ist, dass ngModel erforderlich ist , damit ngOptions funktioniert ... Beachten Sie das, ng-model="blah"was sagt "setze $ scope.blah auf den ausgewählten Wert".

Versuche dies:

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

Hier ist mehr aus der Dokumentation von AngularJS (falls Sie es nicht gesehen haben):

für Array-Datenquellen:

  • Beschriftung für Wert im Array
  • Wählen Sie als Bezeichnung für den Wert im Array
  • Beschriftung Gruppe für Gruppe für Wert im Array = Auswahl als Beschriftung Gruppe für Gruppe für Wert im Array

für Objektdatenquellen:

  • Beschriftung für (Schlüssel, Wert) im Objekt
  • Wählen Sie als Bezeichnung für (Schlüssel, Wert) im Objekt
  • Beschriftung Gruppe für Gruppe für (Schlüssel, Wert) im Objekt
  • Wählen Sie als Bezeichnung Gruppe für Gruppe für (Schlüssel, Wert) im Objekt

Zur Verdeutlichung der Options-Tag-Werte in AngularJS:

Wenn Sie verwenden ng-options, sind die Werte von Options-Tags, die von ng-options geschrieben wurden, immer der Index des Array-Elements, auf das sich das Options-Tag bezieht . Dies liegt daran, dass Sie mit AngularJS tatsächlich ganze Objekte mit ausgewählten Steuerelementen auswählen können und nicht nur primitive Typen. Zum Beispiel:

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>

Mit dem obigen Befehl können Sie ein gesamtes Objekt $scope.selectedItemdirekt auswählen . Der Punkt ist, dass Sie sich mit AngularJS keine Gedanken darüber machen müssen, was in Ihrem Options-Tag enthalten ist. Lassen Sie AngularJS damit umgehen; Sie sollten sich nur darum kümmern, was in Ihrem Modell in Ihrem Bereich enthalten ist.

Hier ist ein Plunker, der das obige Verhalten demonstriert und den ausgeschriebenen HTML-Code zeigt


Umgang mit der Standardoption:

Es gibt einige Dinge, die ich oben in Bezug auf die Standardoption nicht erwähnt habe.

Auswahl der ersten Option und Entfernen der leeren Option:

Sie können dies tun, indem Sie ein einfaches hinzufügen ng-init, das das Modell (von ng-model) auf das erste Element in den Elementen setzt, in denen Sie sich wiederholen ng-options:

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

Hinweis: Dies könnte etwas verrückt werden, wenn fooes richtig auf etwas "Falsches" initialisiert wird. In diesem Fall möchten Sie foohöchstwahrscheinlich die Initialisierung in Ihrem Controller durchführen.

Anpassen der Standardoption:

Das ist etwas anders; Hier müssen Sie lediglich ein Options-Tag als untergeordnetes Element Ihrer Auswahl mit einem leeren Wertattribut hinzufügen und dann den inneren Text anpassen:

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

Hinweis: In diesem Fall bleibt die Option "leer" auch nach Auswahl einer anderen Option erhalten. Dies ist nicht der Fall für das Standardverhalten von Auswahlen unter AngularJS.

Eine benutzerdefinierte Standardoption, die ausgeblendet wird, nachdem eine Auswahl getroffen wurde:

Wenn Sie möchten, dass Ihre angepasste Standardoption nach Auswahl eines Werts nicht mehr angezeigt wird, können Sie Ihrer Standardoption ein ng-hide-Attribut hinzufügen:

<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>
Ben Lesh
quelle
3
Es stellt sich heraus, dass dies die Indizes der Werte sind. Auf diese Weise können Sie mit eckigen Objekten Objekte als Wert für Ihr Auswahlfeld verwenden. Angular erledigt hinter den Kulissen mit Auswahlfeldern eine Menge Dinge für Sie, und Sie sollten sich keine Gedanken über das Wertattribut Ihrer Optionen machen.
Ben Lesh
1
Die Dokumentation befindet sich unter "Auswählen" auf ihrer Website: docs.angularjs.org/api/ng.directive:select
Ben Lesh
25
"... ngModel ist erforderlich, damit ngOptions funktioniert ..." war für mich der Kern des Problems. Gute Antwort.
Tristanm
1
Ist es möglich, die erste leere Option ( <option value="?" selected="selected"></option>) zu vermeiden ?
Swenedo
4
Ich versuche, den letzten Fall zu verwenden ( eine angepasste Standardoption, die ausgeblendet wird, nachdem eine Auswahl getroffen wurde ), habe jedoch einige Probleme festgestellt. Stattdessen musste ng-if="foo"ich ng-if=!foodie leere Standardoption ausblenden, wenn eine andere Option ausgewählt ist. Außerdem wird die leere Standardoption immer am Ende der Kombinationsliste angezeigt. Wie kann ich es an den Anfang der Combo-Liste setzen?
Fran Herrero
90

Ich lerne AngularJS und hatte auch Probleme mit der Auswahl. Ich weiß, dass diese Frage bereits beantwortet ist, aber ich wollte trotzdem etwas mehr Code teilen.

In meinem Test habe ich zwei Listboxen: Automarken und Automodelle. Die Modellliste ist deaktiviert, bis eine Marke ausgewählt ist. Wenn die Auswahl in der Liste "Marken" später zurückgesetzt wird (auf "Marke auswählen" gesetzt), wird die Listenliste "Modelle" wieder deaktiviert UND die Auswahl wird ebenfalls zurückgesetzt (auf "Modell auswählen"). Marken werden als Ressource abgerufen, während Modelle nur fest codiert sind.

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

HTML-Datei:

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

controller.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"};
}
mp31415
quelle
27
Lieber zufälliger Benutzer. Während diese Frage und ihre Antwort recht einfach und unkompliziert sind, zeigt Ihre Organisation des Codes an den richtigen und entsprechenden Stellen (Controller, Service, Vorlage, Daten) die Eleganz von AngularJS in seiner einfachsten und standardmäßigsten Form. Tolles Beispiel.
Atticus
1
So soll es nicht verwendet werden. ng-modelsollte auf eine andere Variable in Ihrem Bereich verweisen , die nicht mit verwandt ist make. Siehe das Beispiel in docs.angularjs.org/api/ng/directive/ngOptions
Dmitri Zaitsev
@DmitriZaitsev Ich denke, Sie liegen falsch, nur weil das eckige Dokumentbeispiel zeigt, wie Sie es beschrieben haben, heißt das nicht, dass dies der einzige Weg ist. Zeigen Sie uns, warum Sie der Meinung sind, dass es nicht auf diese Weise verwendet werden soll, anstatt ein gutes Beispiel für Neulinge zu sein.
JRT
39

Aus irgendeinem Grund lässt AngularJS mich verwirren. Ihre Dokumentation ist diesbezüglich ziemlich schrecklich. Weitere gute Beispiele für Variationen wären willkommen.

Wie auch immer, ich habe eine leichte Variation von Ben Leshs Antwort.

Meine Datensammlungen sehen folgendermaßen aus:

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

Jetzt

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

führte immer noch dazu, dass der Optionswert der Index war (0, 1, 2 usw.).

Hinzufügen von Track By hat es für mich behoben:

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

Ich gehe davon aus, dass es häufiger vorkommt, dass Sie einer Auswahlliste ein Array von Objekten hinzufügen möchten, also werde ich mich an dieses erinnern!

Beachten Sie, dass Sie ab AngularJS 1.4 keine ng-Optionen mehr verwenden können, sondern Folgendes für ng-repeatIhr Options-Tag verwenden müssen:

<select name="test">
   <option ng-repeat="item in items" value="{{item.key}}">{{item.value}}</option>
</select>
Mattijs
quelle
3
Diese Antwort scheint genau das zu sein, wonach die Frage fragt. Jede andere Antwort sagt dem Leser, er solle sich keine Sorgen darüber machen, was HTML generiert wird, aber wenn das Auswahlelement in einer Form vorliegt, mache ich mir große Sorgen. Gute Antwort!
Keith
3
Es sollte darauf hingewiesen werden, dass dies das vollständig ausgewählte Objekt im Modell speichert, nicht nur den Schlüssel. Wenn Sie nur den Schlüssel im Modell haben möchten, möchten Sie die Version "item.key as item.value" verwenden. Dies verwirrte mich eine Weile, als ich aufgehängt wurde, wie der HTML-Code aussah, nicht die Daten, die ich im Modell haben wollte, was für mich das Wichtigste ist.
Mhenry1384
@ mhenry1384 Ja du hast recht, das ganze Objekt zu speichern. Ich mag diese Funktion wirklich, weil Sie damit auf mehr als nur die ID zugreifen können (falls Sie sie benötigen). Funktioniert gut für mich, wenn ich Listen mit einer Mongo-Sammlung fülle und eine Eigenschaft aus dem ausgewählten Element benötige.
Mattijs
2
Und wie können wir Änderungen mit "ng-change" im Inneren erkennen option?
Konstantinos Natsios
2
In Bezug auf das Update sieht dies nicht richtig aus. ng-options funktioniert in 1.5 immer noch einwandfrei. Es wird auch noch in der Dokumentation angezeigt. docs.angularjs.org/api/ng/directive/select
Jeremy A. West
15

Die Frage ist bereits beantwortet (übrigens, wirklich gute und umfassende Antwort von Ben), aber ich möchte der Vollständigkeit halber ein weiteres Element hinzufügen, das auch sehr praktisch sein kann.

In dem von Ben vorgeschlagenen Beispiel:

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

Das folgende ngOptions- Formular wurde verwendet : select as label for value in array.

Label ist ein Ausdruck, dessen Ergebnis das Label für das <option>Element ist. In diesem Fall können Sie bestimmte Zeichenfolgenverkettungen ausführen, um komplexere Optionsbezeichnungen zu erhalten.

Beispiele:

  • ng-options="item.ID as item.Title + ' - ' + item.ID for item in items" gibt Ihnen Etiketten wie Title - ID
  • ng-options="item.ID as item.Title + ' (' + item.Title.length + ')' for item in items"gibt Ihnen Beschriftungen wie Title (X), wo Xist die Länge der Titelzeichenfolge.

Sie können auch Filter verwenden, z.

  • ng-options="item.ID as item.Title + ' (' + (item.Title | uppercase) + ')' for item in items"gibt Ihnen Beschriftungen wie Title (TITLE), wobei der Titelwert der Title-Eigenschaft und TITLE der gleiche Wert ist, jedoch in Großbuchstaben konvertiert wird.
  • ng-options="item.ID as item.Title + ' (' + (item.SomeDate | date) + ')' for item in items"gibt Ihnen Beschriftungen wie Title (27 Sep 2015), wenn Ihr Modell eine Eigenschaft hatSomeDate
Tom
quelle
7

In 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>
Akatsuki Sai
quelle
1
Vergessen Sie nicht Ihre radixfür parseInt: http://davidwalsh.name/parseint-radix
GFoley83
6

Wenn Sie für jede Option einen benutzerdefinierten Titel benötigen, ng-optionsgilt dieser nicht. Verwenden Sie stattdessen ng-repeatmit Optionen:

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

Ich hoffe, dass das Folgende für Sie funktioniert.

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

Es kann nützlich sein. Bindungen funktionieren nicht immer.

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

Beispielsweise füllen Sie das Quellmodell der Optionsliste aus einem REST-Service. Ein ausgewählter Wert war vor dem Ausfüllen der Liste bekannt und wurde festgelegt. Nach dem Ausführen der REST-Anforderung mit $ http ist die Listenoption abgeschlossen.

Die ausgewählte Option ist jedoch nicht festgelegt. Aus unbekannten Gründen bindet AngularJS beim Ausführen von Shadow $ Digest nicht ausgewählt, wie es sein sollte. Ich muss jQuery verwenden, um die Auswahl festzulegen. Es ist wichtig! AngularJS fügt im Schatten das Präfix zum Wert des attr "-Werts" hinzu, der durch ng-repeat-Optionen generiert wird. Für int ist es "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);
           }
       });
}
Trueboroda
quelle