Luckily Angular with its expressiveness allows us develop a solution. Let's create component that takes array of controls and build the form.
@Component({
selector: 'app-root',
template: `<div style="margin: 50px">
<declarative-form [controls]="controls" (submitMe)="onSubmit($event)"></declarative-form>
</div>`
})
export class AppComponent {
controls: Object[] = [
{name: 'name', label: 'Yout name', type: 'text'},
{name: 'name2nd', label: 'Your second name', type: 'text'},
new Control('name3rd', 'Your third name'),
{name : 'description', label: 'Descrition', type: 'textarea' },
new Control('age', 'Your age', 'range'),
new Control('mobile', 'Mobile number'),
new Control('gender', 'Gender', 'radio', {'options' : ['Male', 'Female']}),
new Control('favFood', 'Favourite Food', 'radio', {'options' : ['Pasta', 'Pizza', 'Hamburgers', 'Soups', 'Chinese']}),
new Control('country', 'Country', 'dropdown', {'options': ['US','PL', 'DE']}),
]
onSubmit(values) {
console.log(values);
}
}
Ok, let's start with creating declarative-form component
@Component ({
selector: 'declarative-form',
template: `<form [formGroup]="form" novalidate>
<my-form-input *ngFor="let control of controls"
name="{{control.name}}"
label="{{control.label}}"
type="{{control.type}}"
[params]="control.params"
[form]="form"></my-form-input>
<button type="submit" (click)="onSubmit()">Submit me</button>
</form>
<pre>{{form.value | json}}</pre>`
})
export class DeclarativeFormComponent{
@Input()
controls: Control[];
@Output()
submitMe = new EventEmitter();
form: FormGroup;
constructor(private formBuilder: FormBuilder) {
}
ngOnInit(){
let cfg = new Object();
this.controls.forEach(c => cfg[c.name] = '');
this.form = this.formBuilder.group(cfg);
}
onSubmit(){
console.log(this.form.value);
this.submitMe.emit(this.form.value);
}
}
The ngOnInit function is most tricky here. What it does is creating configuration object for the form builder.
The last missing piece is my-form-input component - your homework ;)