Jak ustawić dynamiczną nazwę modelu w AngularJS?


91

Chcę wypełnić formularz kilkoma dynamicznymi pytaniami (skrzypce tutaj ):

<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}}"]);
    };
}​

Wszystko działa, z wyjątkiem tego, że model to dosłownie Answers ["{{question.Name}}"], zamiast ocenionych odpowiedzi ["GenderQuestion"]. Jak mogę dynamicznie ustawić nazwę tego modelu?

Odpowiedzi:


121

http://jsfiddle.net/DrQ77/

Możesz po prostu wstawić wyrażenie javascript ng-model.


1
Przysięgam, że próbowałem. Dziękuję Ci bardzo. Właściwie poszedłem inną drogą i po prostu ustawiłem model na pytanie.Odpowiedź (opublikuję zaktualizowane skrzypce za chwilę), co okazało się bardziej bezpośrednią odpowiedzią (muszę wyjść z myślenia jQuery), ale wspaniale jest wiedzieć, że rzeczywiście mogę to zrobić tak, jak pierwotnie planowałem na przyszłość. Dzięki jeszcze raz!
— Mike Pateras

Na wypadek, gdyby to pomogło komukolwiek innemu, miałem podobne problemy, ale moim problemem było to, że używałem ng-pattern="field.pattern"tego, czego naprawdę chciałem pattern="{{field.pattern}}". Trochę mylące, że angular zwykle zapewnia pomoc dla dynamicznych atrybutów, ale tym razem napisał swoją własną walidację po stronie klienta i nadał jej tę samą nazwę.
— colllin

Dlaczego zdecydowałeś się stworzyć pusty obiekt (odpowiedzi), skoro nie masz dla niego żadnego celu? Wydaje się, że używasz go tylko w modelu ng, a poza tym nie wydaje się to mieć żadnego celu, więc dlaczego nie pominąć go całkowicie i sprawić, by działał w ten sposób? Czy mógłbyś wyjaśnić?
— Devner

Po prostu próbowałem dokonać minimalnej zmiany w stosunku do oryginalnego kodu. Jeśli spojrzysz na poprawiony kod Mike'a ( jsfiddle.net/2AwLM/23 ), zdecydował się go pozbyć.
— Tosh

Dziękuję bardzo za to. Bardzo mi pomogło. Zobacz tutaj: stackoverflow.com/questions/34081903/…
— Albert,

31

Możesz użyć czegoś takiego scopeValue[field] , ale jeśli twoje pole znajduje się w innym obiekcie, będziesz potrzebować innego rozwiązania.

Aby rozwiązać wszelkiego rodzaju sytuacje, możesz użyć tej dyrektywy:

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);
        }
    };
}]);

Przykład HTML:

<input dynamic-model="'scopeValue.' + field" type="text">

Działa zgodnie z oczekiwaniami.
— C0ZEN

1
Yay! To jest to, czego potrzebowałem! Dziękuję Ci!
— Snapman

2
Ładny. Ale nadal szkoda, że ​​nie możemy po prostu użyć ng-model="{{ variable }}":)
— davidkonrad

13

Skończyło się na tym, że zrobiłem coś takiego:

W kontrolerze:

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

więc w szablonach mógłbym używać całkowicie dynamicznych nazw, a nie tylko pod pewnym zakodowanym elementem (jak w przypadku „Odpowiedzi”):

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

Mam nadzieję że to pomoże.


3

Aby uzupełnić odpowiedź udzieloną przez @abourget, wartość scopeValue [pole] w następnym wierszu kodu może być niezdefiniowana. Spowodowałoby to błąd podczas ustawiania podpola:

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

Jednym ze sposobów rozwiązania tego problemu jest dodanie atrybutu ng-focus = "nullSafe (field)", tak aby kod wyglądał jak poniżej:

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

Następnie definiujesz nullSafe (pole) w kontrolerze, jak poniżej:

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

Gwarantuje to, że scopeValue [pole] nie jest niezdefiniowane przed ustawieniem jakiejkolwiek wartości na scopeValue [pole] [subfield].

Uwaga: nie można użyć funkcji ng-change = "nullSafe (field)", aby osiągnąć ten sam wynik, ponieważ ng-change ma miejsce po zmianie modelu ng, co spowodowałoby błąd, jeśli scopeValue [pole] jest niezdefiniowane.


1

Lub możesz użyć

<select [(ngModel)]="Answers[''+question.Name+'']" ng-options="option for option in question.Options">
        </select>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.