I am trying to write a simple form builder for my clients. The idea being for them to create a simple form that they can use later on different occasions.
For that I am at this point creating a directive to parse the json form back to html trough a directive.
angular
.module('myApp')
.directive('formbuilder', ['$timeout', '$compile', '$parse', function($timeout, $compile, $parse) {
return {
restrict:'AE',
require: 'ngModel',
scope: {
form: '=ngModel'
},
link: function(scope, element, attrs) {
$timeout(function() {
var bones = scope.form.structure;
scope.formId = scope.form.title.replace(/\W+/g, " ").replace(/\s/g,'').toLowerCase();
var html = '<form id="{{formId}}" class="row">';
angular.forEach(bones, function(bone, key) {
if(bone.type == 'text' || bone.type == 'checkbox') {
scope[key] = $parse('form.data.'+key)(scope);
html += '<input-field class="col s12"><input type="'+bone.type+'" id="'+bone.type+key+'" ng-model="form.data['+key+']" /> <label for="'+bone.type+key+'">'+bone.label+'</label></input-field> ';
}
})
html += '<p>{{form.data.input1}}</p>';
html += '</form>';
element.append($compile(html)(scope));
})
}
};
}]);
$scope.form = {
title: 'My first form',
structure: {
input1: {
type: 'text',
label: 'Input label'
},
input2: {
type: 'checkbox',
label: 'This is a checkbox'
},
input3: {
type: 'checkbox',
label: 'This is a CHECKED checkbox'
}
},
data: {
input1: 'Yannick',
input2: false,
input3: true
}
}
I would avoid using the ng-model
attribute which instantiates the ngModelController. Instead use one-time binding:
<formbuilder form="::form"></formbuilder>
In the directive, use isolate scope with one-way (<
) binding:
.directive('formbuilder', ['$timeout', '$compile', '$parse', function($timeout, $compile, $parse) {
return {
restrict:'AE',
/*
require: 'ngModel',
scope: {
form: '=ngModel'
},
*/
scope: { form: "<" },
This will bind the form
object reference to the isolate scope. Changes to the contents by the directive inputs will be shared with the parent scope object. There is no need to do two-way binding of the object reference.
Also for obvious reasons, don't use bracket notation for the property accessor, instead use dot notation:
//html += '<input ng-model="form.data['+key+']"'
//USE dot notation
html += '<input ng-model="form.data.'+key+'"'
The DEMO on PLNKR.