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.