webentwicklung-frage-antwort-db.com.de

Festlegen des ausgewählten Elements in der angleJS-Direktive select

Ich habe ein Problem mit dem Setzen des ausgewählten Elements in der SELECT-Direktive von angle. Ich weiß nicht, ob dies ein Fehler oder ein bewusster Entwurf von den Eckerdesignern ist. Dies macht die select-Direktive jedoch sicherlich weniger nützlich.

Beschreibung:

Meine App kommuniziert mit einer REST - API, um eine Entität aus der Datenbank zu erhalten. Die API schreibt vor, dass Beziehungen des Objekts nur mit einer ID-Eigenschaft gesendet werden, sodass Sie sie bei Bedarf in nachfolgenden Anforderungen abrufen können. 

Beispiel:

{ id : 1, customerName : "some name", city : {id : 12}} 

wobei city eine andere Entität ist, die über einen anderen REST -Endpunkt unter Verwendung der city-ID abgerufen werden kann und so aussieht:

{ id: 12, name : "New York"}

Ich muss ein Formular erstellen, um die Kundenentität mit einem Dropdown-Menü mit allen möglichen Städten zu bearbeiten, sodass der Benutzer die entsprechende Stadt aus der Liste auswählen kann. In der Liste muss zunächst der Ort des Kunden so angezeigt werden, wie er vom JSON-Objekt abgerufen wurde. 

Das Formular sieht so aus: 

 <form>
  <input type="text" ng-model="customer.name"/>
  <select ng-model="customer.city" ng-options="i as i.name for i in cities"></select>
 </form> 

Und der Controller sieht so aus:

app.controller('MainCtrl', function ($scope, $http) {
    $http.get(serviceurl + 'admin/rest/customer/' + id + "/", {
        params: {"accept": "json"},
        withCredentials: true
    }).then(function (response) {
                $scope.customer = response.data.item;
            });
    $http.get(serviceurl + 'admin/rest/city/', {
        params: {"accept": "json"},
        withCredentials: true
    }).then(function (response) {
                $scope.cities = response.data.items;
                // THIS LINE LOADS THE ACTUAL DATA FROM JSON
                $scope.customer.city = $scope.findCity($scope.customer.city);
            });
    $scope.findCity = function (city) {
        for (var i = 0; i < $scope.cities.length; i++) {
            if ($scope.cities[i].id == city.id) {
                return $scope.cities[i];
            }
        }
    }
});

Was sollte passieren: Sobald die vollständigen Details des Stadtobjekts geladen sind, muss die Direktive select die Stadt festlegen, die als ausgewähltes Element in der Liste geladen wurde. 

Was passiert: Die Liste zeigt ein leeres Element an, und es ist nicht möglich, das ausgewählte Element zu initialisieren, wenn das ausgewählte Element aus Objekten außerhalb des Array von Elementen besteht. 

DEMO der Ausgabe hier: http://plnkr.co/edit/NavukDb34mjjnQOP4HE9?p=preview

Gibt es dafür Lösungen? Kann das ausgewählte Element generisch programmgesteuert festgelegt werden, so dass die Aufrufe und Auswahllogik von AJAX in ein wiederverwendbares AJAX - basiertes Auswahl-Widget umgewandelt werden?

19
javito

So einfach ist das

<select
    ng-model="item"
    ng-options="item.name for item in items track by item.name">

Dann in Ihrem Controller:

// all items
$scope.items = [{name: 'a'}, {name: 'b'}, {name: 'c'}];
// set the active one
$scope.item = {name: 'b'};
// or just
$scope.item = $scope.items[1]

Schauen Sie sich die http://docs.angularjs.org/api/ng.directive:select .__ an. Von dort:

trackexpr: Wird verwendet, wenn mit einem Array von Objekten gearbeitet wird. Das Ergebnis dieses Ausdrucks wird zur Identifizierung der Objekte im Array verwendet. Der Trackexpr bezieht sich höchstwahrscheinlich auf die Wertvariable (z. B. value.propertyName).

Der Rest weist der $scope.item-Variablen lediglich einen Wert zu. Winkel wird herausfinden, welches Element als aktiv festgelegt werden soll, indem die name-Eigenschaft des Elements geprüft wird.

41
simo

Der Grund, warum es nicht funktioniert, besteht darin, dass angle erwartet, dass die Objektreferenzen gleich sind. In Ihrem Fall (das 'select from object' in Ihrem Plnkr) erstellt ein neues Objekt, allerdings mit den gleichen Eigenschaften. Angular kann jedoch nicht wissen, dass zwei verschiedene Objekte dasselbe Objekt darstellen. Sie haben mindestens zwei Ansätze:

Finde die richtige Stadtobjektinstanz

Statt $scope.customer.city auf ein neues Objekt zu setzen, suchen Sie das tatsächliche Stadtobjekt aus dem $scope.cities-Array. Wenn Sie UnderscoreJs verwenden, könnten Sie Folgendes tun:

$scope.customer.city = _.find($scope.cities, function (city) {
    return city.id === theCustomersCity.id;
});

An die Stadt-ID anstelle des Stadtobjekts binden

Ein anderer Ansatz, der möglicherweise einfacher ist, besteht darin, die Anweisungen ng-model und ng-options so zu ändern, dass sie mit der ID und nicht mit dem Objekt übereinstimmen. Siehe Arbeitsbeispiel hier .

<select ng-model="customer.cityId" ng-options="i.id as i.name for i in cities"></select>
21
Martin

Ich bin durch dasselbe Problem gekommen. Meine Optionen und die modellierten Daten stammen aus separaten API-Aufrufen.

Anstatt eine Ebene der Indirektion hinzuzufügen, indem ng-model für die Objektschlüssel verwendet wurde, schrieb ich schließlich eine einfache Anweisung, die eine "Proxy" -Variable verwendete.

<select ng-model="customer.city" ng-options="i as i.name for i in cities"></select>

wird

<select ng-model="customer_cityProxy" ng-options="i.name as i.name for i in cities"></select>

Mit einer $ watch auf customer.city und customer_cityProxy erhalte ich das erwartete Verhalten.

Es gibt noch einige Nachteile, da es nur funktioniert, wenn die Tasten disjunkt sind.

Code ist hier verfügbar: https://github.com/gosusnp/options-proxy

2
user1498724

Werfen Sie einen Blick auf http://configit.github.io/ngyn/#select_extensions diese Lösung hat für mich funktioniert

0
danielgatis