Come posso impostare un nome di modello dinamico in AngularJS?


91

Voglio compilare un modulo con alcune domande dinamiche (violino qui ):

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

Tutto funziona, tranne che il modello è letteralmente Risposte ["{{question.Name}}"], invece delle Risposte valutate ["GenderQuestion"]. Come posso impostare dinamicamente il nome del modello?

Risposte:


121

http://jsfiddle.net/DrQ77/

Puoi semplicemente inserire un'espressione javascript in ng-model.


1
Giuro che ci ho provato. Grazie mille. In realtà ho preso una strada diversa e ho impostato il modello su domanda Risposta (metterò un violino aggiornato tra un po '), che si è rivelata una risposta più diretta (devo uscire dalla mentalità jQuery), ma è bello sapere che posso, davvero, farlo nel modo in cui avevo originariamente pianificato per il futuro. Grazie ancora!
Mike Pateras

Nel caso in cui questo aiutasse qualcun altro, avevo problemi simili, ma il mio problema era che stavo usando ng-pattern="field.pattern"quando quello che volevo veramente era pattern="{{field.pattern}}". Un po 'di confusione che angular di solito fornisce un aiuto per gli attributi dinamici, ma questa volta ha scritto la propria convalida lato client e gli ha dato lo stesso nome.
colllin

Perché hai deciso di creare un oggetto vuoto (Risposte) quando non ne hai uno scopo reale? Sembra che tu lo stia usando solo nel modello ng e oltre a questo, non sembra esserci alcuno scopo, quindi perché non ometterlo del tutto e farlo funzionare in quel modo? Potresti chiarire per favore?
Devner

Ho solo provato a fare una modifica minima dal codice originale. Se guardi il codice modificato di Mike ( jsfiddle.net/2AwLM/23 ), ha deciso di sbarazzarsene.
Tosh

Grazie mille per questo. Mi ha aiutato molto. Vedi qui: stackoverflow.com/questions/34081903/…
Albert

31

Puoi usare qualcosa di simile scopeValue[field], ma se il tuo campo è in un altro oggetto avrai bisogno di un'altra soluzione.

Per risolvere tutti i tipi di situazioni, puoi utilizzare questa direttiva:

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

Esempio HTML:

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

Funziona come previsto.
C0ZEN

1
Sìì! Questo è ciò di cui avevo bisogno! Grazie!
Snapman

2
Bello. Ma vorrei ancora che potessimo usare ng-model="{{ variable }}":)
davidkonrad

13

Quello che ho finito per fare è qualcosa del genere:

Nel controller:

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

quindi nei modelli potrei usare nomi totalmente dinamici, e non solo sotto un certo elemento hardcoded (come nel tuo caso "Risposte"):

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

Spero che questo ti aiuti.


3

Per rendere più completa la risposta fornita da @abourget, il valore di scopeValue [campo] nella riga di codice seguente potrebbe essere indefinito. Ciò comporterebbe un errore durante l'impostazione del sottocampo:

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

Un modo per risolvere questo problema è aggiungere un attributo ng-focus = "nullSafe (field)", in modo che il tuo codice sia simile al seguente:

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

Quindi definisci nullSafe (campo) in un controller come il seguente:

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

Ciò garantirebbe che scopeValue [campo] non sia undefined prima di impostare qualsiasi valore su scopeValue [campo] [sottocampo].

Nota: non è possibile utilizzare ng-change = "nullSafe (field)" per ottenere lo stesso risultato perché ng-change si verifica dopo che ng-model è stato modificato, il che genererebbe un errore se scopeValue [field] non è definito.


1

Oppure puoi usare

<select [(ngModel)]="Answers[''+question.Name+'']" ng-options="option for option in question.Options">
        </select>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.