Andreas Andreas - 1 year ago 71
AngularJS Question

Bind dynamically set ng-model attribute for text field

After searching around for hours I am still unable to find an answer to my problem. I am populating a dynamic form with text fields based on values from a database, but am unable to successfully bind the fields to my model. Here's the scenario:

I've got a "project" model in my controller containing lots of project related information (name, start date, participants, category etc), but let's just focus on the "" property for now. In the database I configure "forms" with a number of associated fields, where each field has a property that points to which property it corresponds to in my view model (e.g. ""). At runtime I add these fields to an HTML form dynamically and attempt to set the ng-model attribute to the "modelBinding" value, in this case "".

<div ng-repeat="formField in form.formFields">
<input ng-model="formField.modelBinding" /></div>

This will result in a text box being added to my form, with ng-model="formField.modelBinding" and the textbox value = ''.

What I am trying to achieve is to set ng-model = '', in other words replace formField.modelBinding with the value of formField.modelBinding.

One approach that seemed logical was

<input ng-model = "{{formField.modelBinding}}" />

but this is obviously not going to work. I've tried to insert the HTML tags with ng-bind-html but this seems to only work with ng-bind, not ng-model.

Any suggestions?

Answer Source

Assuming that you are trying to bind a value to a model from a name that you have within the formField you can create a directive (aka ngModelName) to bind your model by name from this value.

Observation: My first thought was using a simple accessor like model[formField.modelBinding] which would simple bind the formField.modelBinding into a model member on scope. However, I didn't use the property accessor because it would create a property named by formField.modelBinding value and not the correct object hierarchy expected. For example, the case described on this question, would create an object { '': 'my data' } but not { 'project': { data: 'my data'}} as it should.

angular.module('myApp', [])
  .directive('ngModelName', ['$compile', function ($compile) {
    return {
        restrict: 'A',
        priority: 1000,
        link: function (scope, element, attrs) {
          scope.$watch(attrs.ngModelName, function(ngModelName) {
                // no need to bind a model
                if (attrs.ngModel == ngModelName || !ngModelName) return;

                element.attr('ng-model', ngModelName);
                // remove ngModel if it's empty
                if (ngModelName == '') {

                // clean the previous event handlers,
                // to rebinded on the next compile

                //recompile to apply ngModel, and rebind events
  .controller('myController', function ($scope) {
    $scope.form = {
      formFields: [
          modelBinding: ''
    $scope.model = {};

angular.element(document).ready(function () {
  angular.bootstrap(document, ['myApp']);  
<script src=""></script>
<div ng-controller="myController">
  <div ng-repeat="formField in form.formFields">
      <input ng-model-name="formField.modelBinding" placeholder="{{ formField.modelBinding }}" />
    <pre>{{ model | json }}</pre>