2012-09-23 12 views
82

Quiero rellenar un formulario con algunas preguntas dinámicas (violín here):¿Cómo puedo establecer un nombre de modelo dinámico en AngularJS?

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

Todo funciona, excepto el modelo es, literalmente, "Respuestas [{{}} question.Name"], en lugar de las respuestas evaluadas ["GenderQuestion"]. ¿Cómo puedo establecer ese nombre de modelo dinámicamente?

Respuesta

112

http://jsfiddle.net/DrQ77/

simplemente Usted puede poner Javascript expresión en ng-model.

+1

Juro que lo intenté. Muchas gracias. De hecho, fui por una ruta diferente, y simplemente puse el modelo en cuestión. Respuesta (Voy a sacar un violín actualizado en un momento), que resultó ser una respuesta más directa (tengo que salir de la mentalidad de jQuery), pero es genial saber que puedo, de hecho, hacerlo de la manera que originalmente planeé para el futuro. ¡Gracias de nuevo! –

+5

Fiddle actualizado: http://jsfiddle.net/2AwLM/23/ –

+0

En caso de que esto ayude a alguien más, estaba teniendo problemas similares, pero mi problema era que estaba usando 'ng-pattern =" field.pattern "' cuando lo que realmente quería era 'pattern =" {{field.pattern}} "'.Más o menos confuso que el angular generalmente proporciona un ayudante para los atributos dinámicos, pero esta vez escribió su propia validación del lado del cliente y le dio el mismo nombre. – colllin

10

Lo que terminé haciendo es algo como esto:

En el controlador:

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

por lo que en las plantillas que podría utilizar nombres totalmente dinámicos, y no sólo en virtud de un determinado elemento no modificable (como en su caso "Respuestas"):

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

Espero que esto ayude.

3

Para que la respuesta proporcionada por @abourget sea más completa, el valor de scopeValue [field] en la siguiente línea de código podría estar indefinido. Esto daría lugar a un error al establecer subcampo:

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

Una forma de resolver este problema es mediante la adición de un atributo ng de enfoque = "nullSafe (campo)", por lo que su código se ve como el siguiente:

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

a continuación, defina nullSafe (campo) en un controlador como el siguiente:

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

Esto garantizaría que scopeValue [campo] no está definido antes de establecer cualquier valor a scopeValue [ámbito] [subcampo ]

Nota: No puede usar ng-change = "nullSafe (field)" para lograr el mismo resultado porque ng-change ocurre después de que se haya cambiado el ng-model, lo que generaría un error si scopeValue [field] es indefinido.

27

Puede usar algo como esto scopeValue[field], pero si su campo está en otro objeto, necesitará otra solución.

Para resolver todo tipo de situaciones, puede utilizar esta directiva:

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

ejemplo HTML:

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

salvó mi día :) – WeMakeSoftware

+0

Funciona como se esperaba. – C0ZEN

+1

¡Yay! Esto es lo que necesitaba! ¡Gracias! – Snapman

Cuestiones relacionadas