Wie kann ich in AngularJS einen dynamischen Modellnamen festlegen?

91

Ich möchte ein Formular mit einigen dynamischen Fragen füllen (Geige hier ):

<div ng-app ng-controller="QuestionController">
    <ul ng-repeat="question in Questions">
        <li>
            <div>{{question.Text}}</div>
            <select ng-model="Answers['{{question.Name}}']" ng-options="option for option in question.Options">
            </select>
        </li>
    </ul>

    <a ng-click="ShowAnswers()">Submit</a>
</div>
​
function QuestionController($scope) {
    $scope.Answers = {};

    $scope.Questions = [
    {
        "Text": "Gender?",
        "Name": "GenderQuestion",
        "Options": ["Male", "Female"]},
    {
        "Text": "Favorite color?",
        "Name": "ColorQuestion",
        "Options": ["Red", "Blue", "Green"]}
    ];

    $scope.ShowAnswers = function()
    {
        alert($scope.Answers["GenderQuestion"]);
        alert($scope.Answers["{{question.Name}}"]);
    };
}​

Alles funktioniert, außer dass das Modell buchstäblich Answers ["{{question.Name}}"] anstelle der ausgewerteten Answers ["GenderQuestion"] ist. Wie kann ich diesen Modellnamen dynamisch festlegen?

Mike Pateras
quelle

Antworten:

121

http://jsfiddle.net/DrQ77/

Sie können einfach einen Javascript-Ausdruck eingeben ng-model.

Tosh
quelle
1
Ich schwöre, ich habe das versucht. Vielen Dank. Ich bin tatsächlich einen anderen Weg gegangen und habe das Modell einfach auf Frage gestellt. Antwort (ich werde gleich eine aktualisierte Geige herausbringen), die sich als direktere Antwort herausstellte (muss aus der jQuery-Denkweise herauskommen), aber Es ist schön zu wissen, dass ich es tatsächlich so machen kann, wie ich es ursprünglich für die Zukunft geplant hatte. Danke noch einmal!
Mike Pateras
Falls dies jemand anderem hilft, hatte ich ähnliche Probleme, aber mein Problem war, dass ich es verwendete, ng-pattern="field.pattern"als das, was ich wirklich wollte, war pattern="{{field.pattern}}". Es ist etwas verwirrend, dass Angular normalerweise einen Helfer für dynamische Attribute darstellt, aber diesmal wurde eine eigene clientseitige Validierung geschrieben und derselbe Name vergeben.
Colllin
Warum haben Sie sich entschieden, ein leeres Objekt (Antworten) zu erstellen, wenn Sie keinen tatsächlichen Zweck dafür haben? Sie scheinen es nur im ng-Modell zu verwenden und abgesehen davon scheint es keinen Zweck zu geben. Warum also nicht ganz weglassen und es so funktionieren lassen? Kannst du das bitte klären?
Devner
Ich habe nur versucht, eine minimale Änderung gegenüber dem ursprünglichen Code vorzunehmen. Wenn Sie sich Mikes überarbeiteten Code ( jsfiddle.net/2AwLM/23 ) ansehen , hat er beschlossen, ihn loszuwerden.
Tosh
Vielen Dank dafür. Hat mir viel geholfen. Siehe hier: stackoverflow.com/questions/34081903/…
Albert
31

Sie können so etwas verwenden scopeValue[field], aber wenn sich Ihr Feld in einem anderen Objekt befindet, benötigen Sie eine andere Lösung.

Um alle Arten von Situationen zu lösen, können Sie diese Anweisung verwenden:

this.app.directive('dynamicModel', ['$compile', '$parse', function ($compile, $parse) {
    return {
        restrict: 'A',
        terminal: true,
        priority: 100000,
        link: function (scope, elem) {
            var name = $parse(elem.attr('dynamic-model'))(scope);
            elem.removeAttr('dynamic-model');
            elem.attr('ng-model', name);
            $compile(elem)(scope);
        }
    };
}]);

HTML-Beispiel:

<input dynamic-model="'scopeValue.' + field" type="text">
William Weckl
quelle
Funktioniert wie erwartet.
C0ZEN
1
Yay! Das habe ich gebraucht! Danke dir!
Snapman
2
Nett. Aber ich wünschte immer noch, wir könnten nur verwenden ng-model="{{ variable }}":)
Davidkonrad
12

Was ich letztendlich gemacht habe, ist ungefähr so:

In der Steuerung:

link: function($scope, $element, $attr) {
  $scope.scope = $scope;  // or $scope.$parent, as needed
  $scope.field = $attr.field = '_suffix';
  $scope.subfield = $attr.sub_node;
  ...

In den Vorlagen konnte ich also völlig dynamische Namen verwenden, und zwar nicht nur unter einem bestimmten fest codierten Element (wie in Ihrem Fall "Antworten"):

<textarea ng-model="scope[field][subfield]"></textarea>

Hoffe das hilft.

abourget
quelle
3

Um die Antwort von @abourget vollständiger zu machen, kann der Wert von scopeValue [Feld] in der folgenden Codezeile undefiniert sein. Dies würde zu einem Fehler beim Einstellen des Unterfelds führen:

<textarea ng-model="scopeValue[field][subfield]"></textarea>

Eine Möglichkeit, dieses Problem zu lösen, besteht darin, ein Attribut ng-focus = "nullSafe (Feld)" hinzuzufügen, sodass Ihr Code wie folgt aussehen würde:

<textarea ng-focus="nullSafe(field)" ng-model="scopeValue[field][subfield]"></textarea>

Dann definieren Sie nullSafe (Feld) in einem Controller wie folgt:

$scope.nullSafe = function ( field ) {
  if ( !$scope.scopeValue[field] ) {
    $scope.scopeValue[field] = {};
  }
};

Dies würde sicherstellen, dass scopeValue [Feld] nicht undefiniert ist, bevor ein Wert auf scopeValue [Feld] [Unterfeld] festgelegt wird.

Hinweis: Sie können ng-change = "nullSafe (Feld)" nicht verwenden, um dasselbe Ergebnis zu erzielen, da ng-change nach dem Ändern des ng-Modells erfolgt. Dies würde einen Fehler auslösen, wenn scopeValue [Feld] nicht definiert ist.

Max
quelle
1

Oder Sie können verwenden

<select [(ngModel)]="Answers[''+question.Name+'']" ng-options="option for option in question.Options">
        </select>
Şafak
quelle