Asignar dinámicamente ng-model

82

Estoy tratando de generar un conjunto de casillas de verificación a partir de una matriz de objetos. Mi objetivo es que las casillas de verificación asignen dinámicamente su modelo ng a una propiedad del nuevo objeto que se enviará a la matriz.

Lo que tenía en mente es algo como

<li ng-repeat="item in items">
    <label>{{item.name}}</label>
    <input type="checkbox" ng-model="newObject.{{item.name}}">
</li>

Esto no funciona como se puede ver en este JSFiddle:

http://jsfiddle.net/GreenGeorge/NKjXB/2/

¿Alguien puede ayudar?

George Ananda Eman
fuente

Respuestas:

146

Esto debería darle los resultados deseados:

<input type="checkbox" ng-model="newObject[item.name]">

Aquí hay un plunk funcional: http://plnkr.co/edit/ALHQtkjiUDzZVtTfLIOR?p=preview

pkozlowski.opensource
fuente
1
hmm en realidad esto literalmente me dio '<input ng-model = "newObject [item.name]">', ¿es algo que me falta?
George Ananda Eman
Hmm, extraño, acabo de agregar un ejemplo en vivo (plunker ya que, por alguna razón, jsFiddle no está funcionando de mi lado hoy).
pkozlowski.opensource
ah sí, estaba acostumbrado a pensar en php y esperaba que el marcado real cambiara al nombre, funcionó. ¡gracias!
George Ananda Eman
2
Brillante, exactamente lo que estaba buscando. ¡Amo Angular!
SharkofMirkwood
1
También funciona muy bien en Angular 2. ¿Pero también hay una solución para objetos multidimensionales? En su ejemplo, si a item.nameveces debería apuntar a newObject['x']y otras a newObject['x']['y'].
Martin Schneider
23

EDITAR Como se señaló correctamente en los comentarios, usar esto con ng-change requiere que un modelo ng "ficticio" esté presente de antemano. Sin embargo, cabe señalar que aparentemente con 1.3 el marco ha proporcionado las opciones necesarias. Consulte https://stackoverflow.com/a/28365515/3497830 a continuación. /EDITAR

En caso de que sea como yo tropezando con un caso simple mientras tengo una tarea más compleja, esta es la solución que se me ocurrió para vincular dinámicamente expresiones arbitrarias a ng-model: http://plnkr.co/edit/ccdJTm0zBnqjntEQfAfx?p = vista previa

Método: Creé una directiva dynamicModel que toma una expresión angular estándar, la evalúa y vincula el resultado al alcance a través de ng-model y $ compile.

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.data = {};
  $scope.testvalue = 'data.foo';
  $scope.eval = $scope.$eval;
});

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.data = {};
  $scope.testvalue = 'data.foo';
  $scope.eval = $scope.$eval;
});

app.directive('dynamicModel', ['$compile', function ($compile) {
    return {
        'link': function(scope, element, attrs) {
            scope.$watch(attrs.dynamicModel, function(dynamicModel) {
                if (attrs.ngModel == dynamicModel || !dynamicModel) return;

                element.attr('ng-model', dynamicModel);
                if (dynamicModel == '') {
                    element.removeAttr('ng-model');
                }

                // Unbind all previous event handlers, this is 
                // necessary to remove previously linked models.
                element.unbind();
                $compile(element)(scope);
            });
        }
    };
}]);

El uso es simplemente modelo dinámico = "expresión angular" donde expresión angular da como resultado una cadena que se utiliza como expresión para ng-modelo.

Espero que esto le ahorre a alguien el dolor de cabeza de tener que encontrar esta solución.

Saludos, Justus

Justus Wingert
fuente
3
Eres un salvavidas. Casi me desesperé antes de encontrar esta publicación.
Nelo Mitranim
¿Puedes ser más específico, Brian? ¿Qué intentaste y qué pasó?
Justus Wingert
Esta es una verdadera joya de solución. Me ha sacado de un problema muy complicado, ¡gracias!
Mikebert4
1
ng-change no funciona con esto. Si observa la fuente angular, la directiva ngChange tiene ngModel como directiva requerida. Una búsqueda rápida muestra que solo ngChange y ngList tienen este problema. Todas las demás directivas parecen tener ngModel como controlador opcional. Resolví este problema agregando un ng-model = "dummyValue" a cualquier elemento usando la directiva de modelo dinámico. Dado que un cambio en el modelo dinámico llama a $ compile, ngChange y cualquier otra directiva que utilice el valor del modelo ng se actualizan correctamente.
EverPresent
1
Esta es una solución más robusta, cuando no es necesario para ver el valor dinámico modelo cambiante - stackoverflow.com/a/32096328/887092
Todd
6

Con Angular 1.3, puede usar la ng-model-optionsdirectiva para asignar dinámicamente el modelo o enlazar a una expresión.

Aquí hay un plunkr: http://plnkr.co/edit/65EBiySUc1iWCWG6Ov98?p=preview

<input type="text" ng-model="name"><br>
<input type="text" ng-model="user.name" 
ng-model-options="{ getterSetter: true }">

Más información ngModelOptionsaquí: https://docs.angularjs.org/api/ng/directive/ngModelOptions

Rob R
fuente
Perdóname si me estoy perdiendo algo, pero nada acerca de tu plunk parece incluir la asignación de modelo dinámico. Y nada sobre ngModelOptions obviamente apoyaría eso. ¿Podrías quizás aclararme? Porque sería muy útil si, de hecho, funcionara de esa manera ...
XML
@XMLilley "getterSetter: valor booleano que determina si se tratan o no las funciones vinculadas a ngModel como getters / setters".
Chris Bolton
Gracias Rob por informarme sobre esto, he actualizado mi respuesta y he vinculado a la tuya.
Justus Wingert
1

Este es mi enfoque para admitir una expresión más profunda, por ejemplo, 'model.level1.level2.value'

<input class="form-control" ng-model="Utility.safePath(model, item.modelPath).value">

donde item.modelPath = 'level1.level2' y Utility (model, 'level1.level2') es la función de utilidad que devuelve model.level1.level2

Kanit Mekritthikrai
fuente
¿Puedes explicar cómo funciona esto? ¿Qué devuelve Utility.safePath de modo que luego pueda usar .value?
Devon Holcombe
Utility.safePath devuelve el valor de la variable anidada especificada por la cadena de ruta. por ejemplo, level1.level2 se refiere a model.level1.level2.
Kanit Mekritthikrai
0

<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>

    <div ng-app="myApp" ng-controller="myCtrl">
        <form name="priceForm" ng-submit="submitPriceForm()">
            <div ng-repeat="x in [].constructor(9) track by $index">
                <label>
                    Person {{$index+1}} <span class="warning-text">*</span>
                </label>
                <input type="number" class="form-control" name="person{{$index+1}}" ng-model="price['person'+($index+1)]" />

            </div>
            <button>Save</button>
        </form>
    </div>

    <script>
        var app = angular.module('myApp', []);
        app.controller('myCtrl', function ($scope) {
            $scope.price = [];
            $scope.submitPriceForm = function () {
                //objects be like $scope.price=[{person1:value},{person2:value}....]
                console.log($scope.price);
            }
        });
    </script>
</body>
</html>

Arun Saini
fuente