Setting input type dynamically is bit tricky, but may be achived with custom directive that appends input to the DOM. From the other hand, inserting inputs to the form dynamically from custom directive you can't enjoy things like myForm.myInput.$error.requred. Besides of it you probably want to add error message and some styling to invalid inputs, therefore you need some CSS.
Here is an example of dynamic form created from JSON with ng-required, ng-maxlength and ng-minlength enabled:
Plunker: http://plnkr.co/edit/F7BGq0sfSLvKE48eDTzQ?p=preview
HTML
<!DOCTYPE html>
<html ng-app="demo">
<head>
<script src="http://code.angularjs.org/1.2.10/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="demoController">
<form name="demoForm">
<div demo-directive ng-repeat="input in inputs"></div>
</form>
</body>
</html>
CSS
.error .required,
.error .minlength,
.error .maxlength {
display: none;
}
.ng-invalid-required + .error .required,
.ng-invalid-minlength + .error .minlength,
.ng-invalid-maxlength + .error .maxlength {
display: inline;
}
.ng-invalid {
outline: 1px solid red;
}
.error {
color: red;
}
JavaScript
angular.module('demo', []).
controller('demoController', function($scope) {
$scope.inputs = [{
inputType: 'checkbox',
name: 'f1',
checked: true,
label: 'input 1',
required: true
}, {
inputType: 'text',
name: 'f2',
value: 'some text 1',
label: 'input 2',
required: true
}, {
inputType: 'file',
name: 'f3',
label: 'input 3'
}, {
inputType: 'text',
name: 'f4',
value: 'some text 2',
label: 'input 2',
min: 2,
max: 15
}];
}).
directive('demoDirective', function($compile) {
return {
template: '<div><label>{{input.label}}: </label></div>',
replace: true,
link: function(scope, element) {
var el = angular.element('<span/>');
switch(scope.input.inputType) {
case 'checkbox':
el.append('<input type="checkbox" name="{{input.name}}" ng-model="input.checked" ng-required="{{input.required}}"/><span class="error"><span class="required">Required!</span></span>');
break;
case 'text':
el.append('<input type="text" name="{{input.name}}" ng-model="input.value" ng-required="{{input.required}}" ng-minlength="{{input.min}}" ng-maxlength="{{input.max}}" /><span class="error"><span class="required">Required!</span><span class="minlength">Minimum length is {{input.min}}!</span><span class="maxlength">Maximum length is {{input.max}}!</span></span>');
break;
case 'file':
el.append('<input type="file" name="{{input.name}}" ng-model="input.value" ng-required="{{input.required}}"/><span class="error"><span class="required">Required!</span></span>');
break;
}
$compile(el)(scope);
element.append(el);
}
}
});