poniedziałek, 15 maja 2017

Angular 2 - Declarative forms

Angular comes with a little bit bloated way of creating forms. Creating each field manually definitely give us full control of how particular fields will look, but on the other hand if there are more then couple fields it is terribly tedious. Moreover, any change requires visiting all places given ux pattern is used (eg. displaying validation errors, labels, etc.)). The declarative way of defining such forms seems to be ideal solution.. but there is no such out of the box.. It's sad.

Luckily Angular with its expressiveness allows us develop a solution. Let's create component that takes array of controls and build the form.

  selector: 'app-root',
  template: `<div style="margin: 50px">
 <declarative-form [controls]="controls" (submitMe)="onSubmit($event)"></declarative-form>
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) {
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"
        <button type="submit" (click)="onSubmit()">Submit me</button>
<pre>{{form.value | json}}</pre>`
export class DeclarativeFormComponent{

  controls: Control[];

  submitMe = new EventEmitter();

  form: FormGroup;

  constructor(private formBuilder: FormBuilder) {

    let cfg = new Object();
    this.controls.forEach(c => cfg[c.name] = '');
    this.form = this.formBuilder.group(cfg);


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 ;)