JSFiddle - React, Tailwind, and code Playground
by maxisam
HTML
<!doctype html>
<html>
<head>
<title>dynamic form</title>
<script src="http://code.angularjs.org/angular-0.9.14.js" ng:autobind></script>
</head>
<body ng:controller="DynFormCtrl">
<my:form ng:repeat="address in addresses" schema="addressSchema" data="address"></my:form>
<div id="model">
addresses = <pre>{{addresses}}</pre>
</div>
</body>
</html>
CSS
fieldset {
padding-bottom: 2em;
}
#model {
position: fixed;
right: 0;
top: 0;
}
JavaScript
function DynFormCtrl() {
// define data we are working with
this.addresses = [{
name: 'John Smith',
friend: true,
address:{line1: '123 Main St.', city:'Anytown', state:'AA', zip:'12345'},
contacts:{type:'phone', value:'1(234) 555-1212'},
notes: 'snort laughs often'
}, {
name: 'Bobo Boom',
address:{line1: '3 Hide St.', city:'Heretown', state:'CA', zip:'12345'},
contacts:{type:'phone', value:'1(234) 555-1212'}
}];
// define schema for the data (each attribute except for 'children' translates to
// DOM element attribute of the same name).
// if 'type' is undefined, it is considered to be 'text'
this.addressSchema = [
{ name: 'name'},
{ name: 'friend', type: 'checkbox'},
{ name: 'address',
children: [
{ name: 'line1' },
{ name: 'city' },
{ name: 'state', size: 2, 'ng:validate': 'regexp:validatorRegExps.state' },
{ name: 'zip', size: 5, 'ng:validate': 'number' }
]
},
{ name: 'contacts',
children: [
{ name: 'type' },
{ name: 'value' }
]
},
{ name: 'notes', type: 'textarea'}
]
this.validatorRegExps = {
state: /[A-Z]{2}/
}
}
angular.widget('my:form', function(element) {
this.directives(true);
return function(element) {
var scope = this,
schema = scope.$eval(element.attr('schema')),
model = element.attr('data'),
fieldset = angular.element('<fieldset></fieldset>');
angular.forEach(schema, function processField(field) {
var name = this.model + '.' + field.name,
fieldElStr;
if (field.children) {
angular.forEach(field.children, processField, {model: name});
return;
}
switch (field.type || 'text') {
...