Dynamically assign ng-model

I'm trying to generate a set of check-boxes from an object array. I'm aiming to have the check-boxes dynamically map their ng-model to a property of the new object that will be submitted into the array.

What I had in mind is something like

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

This doesn't work as can be seen on this JSFiddle:

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

Can anybody help?


Solution 1:

This should give you desired results:

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

Here is a working plunk: http://plnkr.co/edit/ALHQtkjiUDzZVtTfLIOR?p=preview

Solution 2:

EDIT As correctly noted in the comments using this with ng-change requires a "dummy" ng-model to be present beforehand. It should however be noted that apparently with 1.3 the required options have been provided by the framework. Please check out https://stackoverflow.com/a/28365515/3497830 below! /EDIT

Just in case you are like me stumbling over a simple case while having a more complex task, this is the solution I came up with for dynamically binding arbitrary expressions to ng-model: http://plnkr.co/edit/ccdJTm0zBnqjntEQfAfx?p=preview

Method: I created a directive dynamicModel that takes a standard angular expression, evaluates it and links the result to the scope via ng-model and $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);
            });
        }
    };
}]);

Usage is simply dynamic-model="angularExpression" where angularExpression results in a string that is used as the expression for ng-model.

I hope this saves someone the headache of having to come up with this solution.

Regards, Justus

Solution 3:

With Angular 1.3, you can use ng-model-options directive to dynamically assign the model, or bind to an expression.

Here is a 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 }">

More info on ngModelOptions here: https://docs.angularjs.org/api/ng/directive/ngModelOptions

Solution 4:

This is my approach to support deeper expression, e.g. 'model.level1.level2.value'

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

where item.modelPath = 'level1.level2' and Utility(model, 'level1.level2') is the utility function that returns model.level1.level2