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?

Mike Pateras
źródło

Odpowiedzi:

121

http://jsfiddle.net/DrQ77/

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

Bzdury
źródło
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">
William Weckl
źródło
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.

abourget
źródło
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.

Maks
źródło
1

Lub możesz użyć

<select [(ngModel)]="Answers[''+question.Name+'']" ng-options="option for option in question.Options">
        </select>
Şafak
źródło