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?

Antworten:


121

http://jsfiddle.net/DrQ77/

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


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

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.


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.


1

Oder Sie können verwenden

<select [(ngModel)]="Answers[''+question.Name+'']" ng-options="option for option in question.Options">
        </select>
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.