6. Template-DRIVEN & Reactive Forms

ngModel simple two way data binding:

import { Component } from '@angular/core';

@Component({
  selector: 'app-article-editor',
  template: `
          <input [(ngModel)]="title">
          <input [(ngModel)]="title">
          <h2>{{ title }}</h2>
  `
})
export class ArticleEditorComponent {
      title = '';

}

Flesh it out:

import { Component } from '@angular/core';

@Component({
  selector: 'app-article-editor',
  template: `
          <input [ngModel]="title" (ngModelChange)="title=$event">
          <input [ngModel]="title" (ngModelChange)="title=$event">
          <h2>{{ title }}</h2>
  `
})
export class ArticleEditorComponent {
      title = 'Angular conquer the world!';

}

Core bindings of ngModel essentially doing this:

import { Component } from '@angular/core';

@Component({
  selector: 'app-article-editor',
  template: `
          <input [value]="title" (input)="title=$event.target.value">
          <input [value]="title" (input)="title=$event.target.value">
          <h2>{{ title }}</h2>
  `
})
export class ArticleEditorComponent {
      title = 'Let\'s do this.';

}

FormControl basic validation:

import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';

@Component({
  selector: 'app-article-editor',
  template: `
          <p>Technology Name (required):</p>
          <input [formControl]="nameControl" required>
          <button (click)="submitName()">Save</button>
          <h2>{{ name }}</h2>
  `
})
export class ArticleEditorComponent {
      name = '';
      nameControl: FormControl = new FormControl();

      submitName(): void {
        if (this.nameControl.valid) {
          this.name = this.nameControl.value;
        } else {
          alert('You are required');
        }
      }
}

Validators:

import { Component } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';

@Component({
  selector: 'app-article-editor',
  template: `
          <p>Technology Name (required):</p>
          <input [formControl]="nameControl">
          <button (click)="submitName()">Save</button>
          <h2>{{ name }}</h2>
  `
})
export class ArticleEditorComponent {
      name = '';
      nameControl: FormControl = new FormControl(null, Validators.required);

      submitName(): void {
        if (this.nameControl.valid) {
          this.name = this.nameControl.value;
        } else {
          alert('You are required');
        }
      }
}

FormGroup:

import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';

@Component({
  selector: 'app-article-editor',
  template: `
          <p>Title: <input [formControl]="titleControl"></p>
          <p>Text: <input [formControl]="textControl"></p>
          <p><button (click)="saveArticle()">Save</button></p>
          <hr>
          <p>Preview:</p>
          <div style="border: 1px solid #999; margin: 50px;">
            <h1>{{ article.title }}</h1>
            <p>{{ article.text }}</p>
          </div>
  `
})
export class ArticleEditorComponent {
  article: { title: string, text: string } = {title: '', text: ''};
  titleControl: FormControl = new FormControl(null, Validators.required);
  textControl: FormControl = new FormControl(null, Validators.required);
  articleFormGroup: FormGroup = new FormGroup({
    title: this.titleControl,
    text: this.textControl
  });

  saveArticle(): void {
    if (this.articleFormGroup.valid) {
      this.article = this.articleFormGroup.value;
    } else {
      console.log('Missing field(s)!');
    }
  }

}

FormArray:

import { Component } from '@angular/core';
import { FormControl, FormArray, Validators } from '@angular/forms';

@Component({
  selector: 'app-article-editor',
  template: `
            <p>Tags:</p>
            <ul>
              <li *ngFor="let tag of tagCtrls; let i = index;">
                    <input [formControl]="tag">
                    <button (click)="remove(i)">x</button>
              </li>
            </ul>
            <p><button (click)="add()">+</button></p>
            <p><button (click)="saveHer()">Save Her</button></p>
  `
})
export class ArticleEditorComponent {
          tagCtrls: FormControl[] = [];
          tagFormArr: FormArray = new FormArray(this.tagCtrls);

          add(): void {
            this.tagFormArr.push(new FormControl(null, Validators.required));
          }

          remove(idx: number): void {
            this.tagFormArr.removeAt(idx);
          }

          saveHer(): void {
            if (this.tagFormArr.valid) {
              console.log('valid!');
            } else {
              console.log('missing field(s)!');
            }
          }

}

NgForm basic forms:

ngForm ngModel:

import { Component } from '@angular/core';

@Component({
  selector: 'app-article-editor',
  template: `
            <form #f="ngForm" (ngSubmit)="saveHer(f)">
              <p><input ngModel name="title" placeholder="Article Title"></p>
              <p><textarea ngModel name="text" placeholder="Article Text"></textarea></p>
              <p><button type="submit">Save</button></p>
            </form>
  `
})
export class ArticleEditorComponent {
          saveHer(f: any): void {
            console.log(f);
          }

}

ngModelGroup:

import { Component } from '@angular/core';

@Component({
  selector: 'app-article-editor',
  template: `
            <form #f="ngForm" (ngSubmit)="saveHer(f)">
            <div ngModelGroup="article">
              <p><input ngModel name="title" placeholder="Article Title"></p>
              <p><textarea ngModel name="text" placeholder="Article Text"></textarea></p>
            </div>
              <p><button type="submit">Save</button></p>
            </form>
  `
})
export class ArticleEditorComponent {
          saveHer(f: any): void {
            console.log(f);
          }

}

FormBuilder && formControlName:

import { Component, Inject } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-article-editor',
  template: `
            <form [formGroup]="articleGroup" (ngSubmit)="saveHer()">
              <div formGroupName="article">
                <p><input formControlName="title" placeholder="Article Title"></p>
                <p><textarea formControlName="text" placeholder="Article Text"></textarea></p>
              </div>
              <p><button type="submit">Save</button></p>
            </form>
  `
})
export class ArticleEditorComponent {
        articleGroup: FormGroup;

        constructor(@Inject(FormBuilder) formBuilder: FormBuilder) {
          this.articleGroup = formBuilder.group({
            article: formBuilder.group({
            title: [null, Validators.required],
            text: [null, Validators.required]
            })
          });
        }

        saveHer(): void {
          console.log(this.articleGroup);
        }

}

Custom Validator:

import { Component, Inject } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';

@Component({
  selector: 'app-article-editor',
  template: `
              <h2>What I want is to be N°1.</h2>
              <p><textarea [formControl]="bodyCtrl" placeholder="Article Text"></textarea></p>
              <p><button (click)="saveHer()">Save</button></p>
  `
})
export class ArticleEditorComponent {
        articleBody = '';
        bodyCtrl: FormControl = new FormControl(null, [Validators.required, this.wordCtrlValidator]);

        wordCtrlValidator(c: any): {[key: string]: any} {
          if (c.value) {
          const wordCt: number = (c.value.match(/\S+/g) || []).length;
          return wordCt <=10 ? null : { 'maxwords': {'limit': 10, 'actual': wordCt }};
          }
        }

        saveHer(): void {
          this.bodyCtrl.valid ? console.log('valid!') : console.log('invalid!');
        }

}

Refactor Validator into its own directive:

import { Directive } from '@angular/core';
import { Validator, FormControl, NG_VALIDATORS } from '@angular/forms';

@Directive({
  selector: '[appMaxWordCountValidator]',
  inputs: ['rawCount: appMaxWordCountValidator'],
  providers: [{
    provide: NG_VALIDATORS,
    useExisting: MaxWordCountValidatorDirective,
    multi: true
  }]
})
export class MaxWordCountValidatorDirective implements Validator {
  rawCount = '';
  validate(c: FormControl): {[key: string]: any} {
    const wordCt: number = ((c.value || '').match(/\S+/g) || []).length;
    return wordCt <= this.maxCount ? null : { 'maxwords': {'limit': this.maxCount, 'actual': wordCt }};
  }
  get maxCount(): number {
    return parseInt(this.rawCount, 10);
  }

}

Custom asynchronous validator with promise:

import { FormControl, Validator } from '@angular/forms';

export class DelayValidator implements Validator {

  static validate(c: any): Promise<{[key: string]: any}> {
    if (c.pristine && !c.value) {
      return new Promise;
    }

    if (!c.delayPromise) {
      c.delayPromise = new Promise((resolve) => {
        setTimeout(() => {
          console.log('resolve');
          resolve();
        }, 3000);
      });
    }
  return c.delayPromise;
  }

}

results matching ""

    No results matching ""