AngularJS - Wertattribut für select

72

JSON-Quelldaten sind:

[
  {"name":"Alabama","code":"AL"},
  {"name":"Alaska","code":"AK"},
  {"name":"American Samoa","code":"AS"},
  ...
]

ich versuche

ng-options="i.code as i.name for i in regions"

aber ich bekomme:

<option value="?" selected="selected"></option>
<option value="0">Alabama</option>
<option value="1">Alaska</option>
<option value="2">American Samoa</option>

während ich erwarte zu bekommen:

<option value="AL">Alabama</option>
<option value="AK">Alaska</option>
<option value="AS">American Samoa</option>

Also, wie man Wertattribute erhält und "?" Artikel?

Übrigens, wenn ich die $ scope.regions auf einen statischen JSON anstelle des Ergebnisses der AJAX-Anfrage setze, verschwindet das leere Element.

Paul
quelle
1
Mögliches Duplikat von Warum enthält anglejs eine leere Option in select
ZeroOne
2
Verwenden Sie - region in regions track by region.codeum das Wertattribut auf den Wert region.code zu setzen;)
taystack

Antworten:

75

Was Sie zuerst versucht haben, sollte funktionieren, aber der HTML-Code entspricht nicht unseren Erwartungen. Ich habe eine Option hinzugefügt, um den anfänglichen Fall "Kein Element ausgewählt" zu behandeln:

<select ng-options="region.code as region.name for region in regions" ng-model="region">
   <option style="display:none" value="">select a region</option>
</select>
<br>selected: {{region}}

Das obige generiert diesen HTML:

<select ng-options="..." ng-model="region" class="...">
   <option style="display:none" value class>select a region</option>
   <option value="0">Alabama</option>
   <option value="1">Alaska</option>
   <option value="2">American Samoa</option>
</select>

Geige

Obwohl Angular numerische Ganzzahlen für den Wert verwendet, wird das Modell (dh $ scope.region) je nach Wunsch auf AL, AK oder AS gesetzt. (Der numerische Wert wird von Angular verwendet, um den richtigen Array-Eintrag zu suchen, wenn eine Option aus der Liste ausgewählt wird.)

Dies kann verwirrend sein, wenn Sie zum ersten Mal erfahren, wie Angular seine Direktive "select" implementiert.

Mark Rajcok
quelle
14
Ich finde es verwirrend und ein Mangel an Transparenz, dass der HTML-
Code
3
Es ist eine andere Denkweise. Sie wählen tatsächlich ein region Objekt aus , keine region.code Zeichenfolge . Sobald der Benutzer etwas ausgewählt hat, wird das region Objekt ausgewählt. Wenn Sie den Code später möchten, greifen Sie einfach zu region.code. Hoffentlich hilft das.
Jess
3
Kann jemand erklären, was genau die Syntax "region.code as region.name" eigentlich "sagt" ... es scheint mir nur wenig sinnvoll zu sein. Dieses "als" -Schlüsselwort wirft mich einfach komplett um, weil ich denke, dass es keinen grammatikalischen Nutzen hat, um auf irgendeine Art von Bedeutung zu schließen.
ProxyTech
4
@ProxyTech, ich denke so: Verwenden Sie region.code für die Werte, die dem Modell zugewiesen werden sollen, aber zeigen Sie dem Benutzer region.name an. Die API-Dokumente beziehen sich auf den Teil region.name als label.
Mark Rajcok
3
@MarkRajcok Es ist mein C # -Paradigma, das zu Verwirrung mit dem Schlüsselwort "as" führt, das zum Umwandeln von Typ zu Typ verwendet wird. Dann gibt es mein "englischsprachiges" Paradigma, bei dem das Schlüsselwort "als" bedeutet, dass "region.came" "region.code" interagiert / ersetzt ... im Kontext völlig nicht der Fall. Einfach sehr schlechte Syntax meiner Meinung nach.
ProxyTech
26

Sie können dies nur dann wirklich tun, wenn Sie sie selbst in einer ng-Wiederholung erstellen.

<select ng-model="foo">
   <option ng-repeat="item in items" value="{{item.code}}">{{item.name}}</option>
</select>

ABER ... es ist es wahrscheinlich nicht wert. Es ist besser, es so zu lassen, wie es entworfen wurde, und Angular das Innenleben überlassen. Angular verwendet den Index auf diese Weise, sodass Sie tatsächlich ein gesamtes Objekt als Wert verwenden können. Sie können also eine Dropdown-Bindung verwenden, um einen ganzen Wert und nicht nur eine Zeichenfolge auszuwählen, was ziemlich beeindruckend ist:

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

{{foo | json}}
Ben Lesh
quelle
3
Obwohl Ihr erstes Beispiel eine funktionierende / korrekte Auswahlliste erstellt und Sie davor gewarnt haben, sie zu verwenden, beachten Sie, dass sie mit dem Rest von Angular nicht gut funktioniert. Dies funktioniert beispielsweise nicht wie erwartet: <a ng-click="foo ='AK'"> AK auswählen </a>. Im Allgemeinen sollte das value-Attribut wahrscheinlich nicht mit der Angular-Select-Direktive verwendet werden.
Mark Rajcok
Dies ist ein fantastischer Weg, um einen lang andauernden Fehler zu umgehen track byund selectnicht zusammenzuarbeiten. Siehe hier für den Fehlerbericht: github.com/angular/angular.js/issues/6564
Jack M.
22

Wenn Sie die track byOption verwenden, ist das valueAttribut korrekt geschrieben, z.

<div ng-init="a = [{label: 'one', value: 15}, {label: 'two', value: 20}]">
    <select ng-model="foo" ng-options="x for x in a track by x.value"/>
</div>

produziert:

<select>
    <option value="" selected="selected"></option>
    <option value="15">one</option>
    <option value="20">two</option>
</select>
Joscha
quelle
1
Dies funktioniert perfekt in Angular 1.3 kittyminky, überprüfen Sie Ihre Syntax vielleicht. - Dies sollte die ausgewählte Antwort sein.
Taystack
7

Wenn das für die Dropdown-Liste angegebene Modell nicht vorhanden ist, generiert Angular ein leeres Optionselement. Sie müssen das Modell in der Auswahl also explizit wie folgt angeben:

<select ng-model="regions[index]" ng-options="....">

Beziehen Sie sich auf Folgendes, wie es zuvor beantwortet wurde:

Warum enthält AngularJS eine leere Option in select? und diese Geige

Update: Versuchen Sie dies stattdessen:

<select ng-model="regions[index].code" ng-options="i.code as i.name for i in regions">
</select>

or

<select ng-model="regions[2]" ng-options="r.name for r in regions">
</select>

Beachten Sie, dass die Auswahl kein leeres Optionselement enthält.

msyed
quelle
5

Sie können Ihr Modell so ändern, dass es folgendermaßen aussieht:

$scope.options = {
    "AL" : "Alabama",
    "AK" : "Alaska",
    "AS" : "American Samoa"
  };

Dann benutze

<select ng-options="k as v for (k,v) in options"></select>
Olivier.Roger
quelle
Diese Variante funktioniert nicht. Es werden entweder Optionen mit demselben numerischen Wert und Text oder Optionen mit einem numerischen Wert und leerem Text in Abhängigkeit von der Reihenfolge erzeugt: "k als v" oder "v als k"
Paul
4

Es scheint nicht möglich zu sein, den "Wert" einer Auswahl in irgendeiner sinnvollen Weise als normales HTML-Formularelement zu verwenden und ihn auch auf genehmigte Weise mit ng-options an Angular anzuschließen. Als Kompromiss musste ich schließlich eine versteckte Eingabe neben meine Auswahl setzen und sie das gleiche Modell wie meine Auswahl verfolgen lassen (alles aus Gründen der Kürze sehr stark von echtem Produktionscode vereinfacht):

HTML:

<select ng-model="profile" ng-options="o.id as o.name for o in profiles" name="something_i_dont_care_about">
</select>
<input name="profile_id" type="text" style="margin-left:-10000px;" ng-model="profile"/>

Javascript:

App.controller('ConnectCtrl',function ConnectCtrl($scope) {
$scope.profiles = [{id:'xyz', name:'a profile'},{id:'abc', name:'another profile'}];
$scope.profile = -1;
}

Dann habe ich in meinem serverseitigen Code nur gesucht params[:profile_id](dies war zufällig eine Rails-App, aber das gleiche Prinzip gilt überall). Da die versteckten Eingaben dasselbe Modell wie die Auswahl verfolgen, bleiben sie automatisch synchron (kein zusätzliches Javascript erforderlich). Dies ist der coole Teil von Angular. Es gleicht fast aus, was es als Nebeneffekt mit dem Wertattribut macht.

Interessanterweise stellte ich fest, dass diese Technik nur mit Eingabe-Tags funktioniert, die nicht ausgeblendet waren (weshalb ich den Rand links verwenden musste: -10000px; Trick, um die Eingabe von der Seite zu verschieben). Diese beiden Varianten haben nicht funktioniert:

<input name="profile_id" type="text" style="display:none;" ng-model="profile"/>

und

<input name="profile_id" type="hidden" ng-model="profile"/>

Ich denke, das muss bedeuten, dass mir etwas fehlt. Es scheint zu seltsam, um ein Problem mit Angular zu sein.

Tim Cull
quelle
Sie können <input name="profile_id" type="hidden" value="{{profile}}"/>auch verwenden. Es klappt.
Harrrrrrry
1

Sie können verwenden

state.name for state in states track by state.code

Bei Zuständen im JSON-Array ist state der Variablenname für jedes Objekt im Array.

Hoffe das hilft

lazell
quelle
-2

Versuchen Sie es wie folgt:

var scope = $(this).scope();
alert(JSON.stringify(scope.model.options[$('#selOptions').val()].value));
blackHu
quelle