Comment puis-je définir un nom de modèle dynamique dans AngularJS?


91

Je veux remplir un formulaire avec des questions dynamiques (violon ici ):

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

Tout fonctionne, sauf que le modèle est littéralement Answers ["{{question.Name}}"], au lieu des Answers évalués ["GenderQuestion"]. Comment puis-je définir ce nom de modèle de manière dynamique?

Réponses:


121

http://jsfiddle.net/DrQ77/

Vous pouvez simplement insérer une expression javascript ng-model.


1
Je jure que j'ai essayé ça. Merci beaucoup. En fait, j'ai emprunté une voie différente, et j'ai simplement mis le modèle en question.Réponse (je vais publier un violon mis à jour dans un instant), ce qui s'est avéré être une réponse plus directe (je dois sortir de l'état d'esprit jQuery), mais c'est formidable de savoir que je peux, en effet, le faire de la manière dont j'avais initialement prévu pour l'avenir. Merci encore!
Mike Pateras

Au cas où cela aiderait quelqu'un d'autre, j'avais des problèmes similaires, mais mon problème était que j'utilisais ng-pattern="field.pattern"quand ce que je voulais vraiment était pattern="{{field.pattern}}". Un peu déroutant, angular fournit généralement une aide pour les attributs dynamiques, mais cette fois, il a écrit sa propre validation côté client et lui a donné le même nom.
colllin

Pourquoi avez-vous décidé de créer un objet vide (Answers) alors que vous n'avez aucun but réel? Vous semblez l'utiliser uniquement dans le modèle ng et à part cela, il ne semble pas y avoir de but, alors pourquoi ne pas l'omettre complètement et le faire fonctionner de cette façon? Pourriez-vous clarifier?
Devner

J'ai juste essayé de faire un changement minimum par rapport au code d'origine. Si vous regardez le code révisé de Mike ( jsfiddle.net/2AwLM/23 ), il a décidé de s'en débarrasser.
Tosh

Merci beaucoup pour cela. M'a beaucoup aidé. Voir ici: stackoverflow.com/questions/34081903/…
Albert

31

Vous pouvez utiliser quelque chose comme ça scopeValue[field], mais si votre champ est dans un autre objet, vous aurez besoin d'une autre solution.

Pour résoudre toutes sortes de situations, vous pouvez utiliser cette directive:

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

Exemple HTML:

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

Fonctionne comme prévu.
C0ZEN

1
Yay! C'est ce dont j'avais besoin! Je vous remercie!
Snapman

2
Agréable. Mais je souhaite toujours que nous puissions simplement utiliser ng-model="{{ variable }}":)
davidkonrad

13

Ce que j'ai fini par faire, c'est quelque chose comme ça:

Dans le contrôleur:

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

donc dans les modèles, je pourrais utiliser des noms totalement dynamiques, et pas seulement sous un certain élément codé en dur (comme dans votre cas "Answers"):

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

J'espère que cela t'aides.


3

Pour rendre la réponse fournie par @abourget plus complète, la valeur de scopeValue [champ] dans la ligne de code suivante peut être indéfinie. Cela entraînerait une erreur lors de la définition du sous-champ:

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

Une façon de résoudre ce problème consiste à ajouter un attribut ng-focus = "nullSafe (field)", afin que votre code ressemble à ce qui suit:

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

Ensuite, vous définissez nullSafe (champ) dans un contrôleur comme ci-dessous:

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

Cela garantirait que scopeValue [champ] n'est pas indéfini avant de définir une valeur sur scopeValue [champ] [sous-champ].

Remarque: Vous ne pouvez pas utiliser ng-change = "nullSafe (field)" pour obtenir le même résultat car ng-change se produit après la modification du ng-model, ce qui générerait une erreur si scopeValue [field] n'est pas défini.


1

Ou vous pouvez utiliser

<select [(ngModel)]="Answers[''+question.Name+'']" ng-options="option for option in question.Options">
        </select>
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.