91 votes

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

Je veux remplir un formulaire avec des questions dynamiques (fiddle). aquí ):

<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 de l'évalué Answers["GenderQuestion"]. Comment puis-je définir ce nom de modèle de manière dynamique ?

122voto

Tosh Points 13477

http://jsfiddle.net/DrQ77/

Vous pouvez simplement mettre l'expression javascript dans ng-model .

32voto

William Weckl Points 2307

Vous pouvez utiliser quelque chose comme ceci scopeValue[field] Mais si votre champ se trouve 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">

13voto

abourget Points 756

Ce que j'ai fini par faire 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;
  ...

Ainsi, 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 "Réponses") :

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

J'espère que cela vous aidera.

2voto

Ming Points 50

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

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

Une façon de résoudre ce problème est d'ajouter un attribut ng-focus="nullSafe(field)", de sorte que votre code ressemblerait à celui ci-dessous :

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

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

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

Cela garantirait que scopeValue[field] n'est pas indéfini avant de définir une valeur quelconque dans scopeValue[field][subfield].

Remarque : vous ne pouvez pas utiliser ng-change="nullSafe(field)" pour obtenir le même résultat car ng-change intervient après la modification du ng-model, ce qui entraînerait une erreur si scopeValue[field] est indéfini.

1voto

Şafak Points 32

Ou vous pouvez utiliser

<select [(ngModel)]="Answers[''+question.Name+'']" ng-options="option for option in question.Options">
        </select>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X