Bufke Bufke - 21 days ago 8
AngularJS Question

Set angularjs input directive name as a variable

I'm trying to set an input like

<form name="myForm">
<input name="{{ name }}"/>
</form>


It works in the dom. I see

<input name="whatever_name_is_set_to"/>


However in my ngForm I have

$scope.myForm: {
{{ name }}: { }
}


Doh'

Why am I doing this? I'm trying to create a directive so that I can build my forms programmatically. Then I can do something like

<div my-field
name="credits"
field="course.credits"
field-options="courseOptions.credits"
title="Credits"
></div>


Plunker

Answer

I just answered a similar question yesterday about dynamically named form elements. In short, no, you can't use interpolation to dynamically name your form fields - the interpolation string will end up in the field name as you have seen.

In your case you're probably going to need to look into dynamically compiling the input HTML inside your myField directive.

Here is a simplified example using $compile to dynamically generate form elements: http://jsfiddle.net/Sly_cardinal/XKYJ3/

HTML:

<div ng-app="myApp">
    <form name="myForm" ng-controller="myController">
        <div my-field 
             name="courseName"
             field="course.courseName"
             title="Course Name"></div>

        <div my-field 
             name="credits"
             field="course.credits"
             title="Credits"></div>

        <!-- Show that the values are bound. -->
        <pre>course: {{course | json:'  '}}</pre>
        <!-- Show that the field is being registered with the ngFormController. -->
        <pre>myForm.credits.$dirty: {{myForm.credits.$dirty}}</pre>
    </form>
</div>

JavaScript:

angular.module('myApp', [])
.controller('myController', ['$scope', function($scope){
    $scope.course = {
        credits: 100,
        courseName: 'Programming 201'
    };
}])
.directive('myField', ['$compile', '$parse', function($compile, $parse){
    // In a real project you'd probably want to use '$templateCache' instead
    // of having strings in your code.
    var tmpl = $compile('<label>{{title}}</label>');

    return {
        scope: true,
        link: function(scope, element, attr){
            scope.title = attr.title;

            var newEl = angular.element('<input type="text"/>');
            newEl.attr('ng-model', attr.field);
            newEl.attr('name', attr.name);

            tmpl(scope, function(fieldEl, scope){
                $compile(newEl[0].outerHTML)(scope, function(el, scope){
                    fieldEl.append(el);
                    element.append(fieldEl);
                });
            });
        }
    }
}]);

A note on this example:

This is a very specific situation - generating dynamic form elements - that requires the use of $compile. This is not the "go to" solution when working with Angular inputs and forms - Angular will handle all the common situations with directives, data-binding and everything else the framework provides. Plus, as Marc Kline's comment shows, it looks like at some point Angular will handle dynamic form management itself at some point in the future.

If you were to continue down the path using $compile to generate these form elements then you'd probably want to use the $templateCache to manage your templates so you're not trying to manage template strings inside your directive.

Comments