it-swarm.com.de

Angularjs ng-options mit Nummer für Modell wählen keinen Anfangswert aus

Ich versuche, ng-options mit einem <select> zu verwenden, um einen numerischen Integerwert an eine Liste entsprechender Optionen zu binden. In meinem Controller habe ich so etwas:

myApp.controller('MyCtrl', function() {
    var self = this;

    var unitOptionsFromServer = {
        2: "mA",
        3: "A",
        4: "mV",
        5: "V",
        6: "W",
        7: "kW"
    };

    self.unitsOptions = Object.keys(unitOptionsFromServer).map(function (key) {
        return { id: key, text: unitOptionsFromServer[key] };
    });

    self.selectedUnitOrdinal = 4; // Assume this value came from the server.
});

HTML: 

<div ng-controller="MyCtrl as ctrl">
    <div>selectedUnitOrdinal: {{ctrl.selectedUnitOrdinal}}</div>
    <select ng-model="ctrl.selectedUnitOrdinal" ng-options="unit.id as unit.text for unit in ctrl.unitsOptions"></select>
</div>

Und hier ist ein jsFiddle , das das Problem demonstriert, und einige andere Ansätze, die ich unternommen habe, aber ich bin nicht zufrieden damit.

Die Auswahloption wird mit einem leeren Wert anstelle von "mV" initialisiert, wie in diesem Beispiel erwartet. Die Bindung scheint einwandfrei zu funktionieren, wenn Sie eine andere Option auswählen - selectedUnitOrdinal wird ordnungsgemäß aktualisiert.

Ich habe festgestellt, dass wenn Sie den anfänglichen Modellwert auf eine Zeichenfolge statt auf eine Zahl setzen, die erste Auswahl funktioniert (siehe Punkt 3 in der Geige).

Ich möchte wirklich, dass ng-options Nice mit numerischen Optionswerten spielt. Wie kann ich das elegant erreichen?

57
BrandonLWhite

In der Dokumentation von Angular für die ng-select-Direktive wird erläutert, wie Sie dieses Problem lösen können. Siehe https://code.angularjs.org/1.4.7/docs/api/ng/directive/select (letzter Abschnitt).

Sie können eine convert-to-number-Direktive erstellen und auf Ihr select-Tag anwenden:

JS:

module.directive('convertToNumber', function() {
  return {
    require: 'ngModel',
    link: function(scope, element, attrs, ngModel) {
      ngModel.$parsers.Push(function(val) {
        return val != null ? parseInt(val, 10) : null;
      });
      ngModel.$formatters.Push(function(val) {
        return val != null ? '' + val : null;
      });
    }
  };
});

HTML:

<select ng-model="model.id" convert-to-number>
  <option value="0">Zero</option>
  <option value="1">One</option>
  <option value="2">Two</option>
</select>

Hinweis: Ich habe festgestellt, dass die Direktive aus dem Dokument keine Nullwerte behandelt, also musste ich sie etwas anpassen.

96
Christophe L

Vielleicht ist es etwas chaotisch, aber das Ergebnis kann ohne spezielle Funktionen direkt in den ng-Optionen erzielt werden

<select ng-model="ctrl.selectedUnitOrdinal" ng-options="+(unit.id) as unit.text for unit in ctrl.unitsOptions"></select>
37
re-gor

Wenn Sie die unit.id erhalten, wird eine Zeichenfolge und keine Ganzzahl zurückgegeben. Objekte in Javascript speichern ihre Schlüssel als Zeichenfolgen. Der einzige Weg, dies zu tun, besteht darin, dass Sie 4 durch Zitate umgeben.

Bearbeiten

<select ng-model="ctrl.selectedUnitOrdinal" ng-options="convertToInt(unit.id) as unit.text for unit in ctrl.unitsOptions"></select>

$scope.convertToInt = function(id){
    return parseInt(id, 10);
};
15
Mathew Berg

Sie können auch den Filter number definieren. Dieser Filter analysiert den Zeichenfolgenwert automatisch in int:

<select ng-model="ctrl.selectedUnitOrdinal" ng-options="unit.id|number as unit.text for unit in ctrl.unitsOptions"></select>


angular.module('filters').filter('number', [function() {
        return function(input) {
            return parseInt(input, 10);
        };
    }]);
9
zooblin

Nur um Christophe's Antwort hinzuzufügen: Der einfachste Weg, zu erreichen und zu pflegen, ist es, eine Richtlinie zu erlassen:

JS:

.directive('convertToNumber', function() {
  return {
    require: 'ngModel',
    link: function(scope, element, attrs, ngModel) {
      ngModel.$parsers.Push(function(val) {
        //saves integer to model null as null
        return val == null ? null : parseInt(val, 10);
      });
      ngModel.$formatters.Push(function(val) {
        //return string for formatter and null as null
        return val == null ? null : '' + val ;
      });
    }
  };
});

Die Antwort von Christophe funktioniert nicht korrekt für '0', da sie bei 'val?' Falsch ist. Prüfung.

8
s3r3k

Angular sieht Ihre id-Eigenschaft als Zeichenfolge, und fügen Sie Anführungszeichen hinzu:

self.selectedUnitOrdinal = "4";
3
tymeJV

Ganz ähnlich wie die Antwort von tymeJV besteht die einfache Problemumgehung darin, die Standardauswahlnummer in eine Zeichenfolge wie folgt zu konvertieren:

self.selectedUnitOrdinal = valueThatCameFromServer.toString();

Auf diese Weise müssen Sie die Zahl nicht fest codieren. Sie können nur jeden erhaltenen Wert konvertieren. Es ist eine einfache Lösung ohne Filter oder Anweisungen.

3
emil.c

Ich denke, die anderen Lösungen sind zu komplex, wenn der Wert einfach als ganze Zahl festgelegt wird. Ich würde ... benutzen:

<select ng-model="model.id">
    <option ng-value="{{ 0 }}">Zero</option>
    <option ng-value="{{ 1 }}">One</option>
    <option ng-value="{{ 2 }}">Two</option>
</select>
2
Ted Scheckler

Machen Sie id-Eigenschaft in unitsOptions als Zahl

self.unitsOptions = Object.keys(unitOptionsFromServer).map(function (key) {
        return { id: +key, text: unitOptionsFromServer[key] };
    });

http://jsfiddle.net/htwc10nx/

1
oadcub
<select ng-model="ctrl.selectedUnitOrdinal" ng-options="+(unit.id) as unit.text for unit in ctrl.unitsOptions"></select>
0
mangesh

Während die von Mathew Berg gelieferte Lösung funktioniert, werden wahrscheinlich andere Auswahlmöglichkeiten, die sting-wertige Auswahloptionen verwenden, nicht funktionieren. Dies kann ein Problem sein, wenn Sie versuchen, eine universelle Direktive für die Behandlung von Selects zu schreiben (wie ich es tat). 

Eine schöne Problemumgehung besteht darin, zu prüfen, ob der Wert eine Zahl ist (auch wenn es sich um eine Zeichenfolge handelt, die eine Zahl enthält) und nur dann die Konvertierung durchführen, wie dies z.

angular.module('<module name>').filter('intToString', [function() {
        return function(key) {
            return (!isNaN(key)) ? parseInt(key) : key;
        };
    }]);

oder als Controller-Methode:

$scope.intToString = function(key) {
    return (!isNaN(key)) ? parseInt(key) : key;
};
0
bwitkowicz