udemy.angular/docs/forms.md
2021-12-15 15:41:21 +01:00

6.8 KiB

Forms

Angular offers two different approach to retrieving data from a from.

  • Template-driven (predefined)
  • Reactive (Manual setup but flexible)

Template driven

Creating the Form and registering the controls

Import the Form module in the app.module.ts.

import { FormsModule } from '@angular/forms';

@NgModules({
    imports: [ FormsModule ]
})

Register the imput with the ngModel directive.

overview

Submitting and using the Form

app.component.html

<form (ngSubmit)="onSubmit(f)" #f="ngForm">

app.component.ts

onSubmit(form: ngForm) {
    console.log(form);
}
overview

@ViewChild

Here we can retrive the data also without submitting the form

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

export class AppComponent {
    @ViewChild('f') signupForm: ngForm;

    onSubmit() {
        console.log(this.signupForm);
}

FormValidation

By adding an attribute like required, email to the html form. Angular detects as a directive and validates it automatically.

Angular Validators

Using the Form state

<button 
    type="submnit"
    [disabled]="!f.valid">Submit</button>

The f referes to the local reference declaredy§ in the form.

Visually can be showen that a input is invalid by adding this CSS definition.

input.ng-invalid.ng-touched {
    border: 1px solid red;
}

It shows only a red boder when the input field has been modified.

Showing some hint text

 <label for="email">Mail</label>
            <input
              type="email"
              id="email"
              class="form-control"
              ngModel
              name="email"
              required
              email
              #email="ngModel">
            <span class="help-block" *ngIf="!email.valid && email.touched">Please enter a valid email!</span>

setValue and patchValue helps to preset the form with predefined values. With setValue overrides the whole form, and patchValue updates only a specific inputfield. patchValue is aviable only from the form (signupForm.form.patchValue({userData: { username: 'bliblubla'}});).

Reactive driven

Import the Form module in the app.module.ts.

import { ReactiveFormsModule } from '@angular/forms';

@NgModules({
    imports: [ ReactiveFormsModule ]
})

app.component.html

<div class="container">
  <div class="row">
    <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
      <form [formGroup]="signupForm" (ngSubmit)="onSubmit()">
        <div formGroupName="userData">
          <div class="form-group">
            <label for="username">Username</label>
            <input
              type="text"
              id="username"
              formControlName="username"
              class="form-control">
            <span
              *ngIf="!signupForm.get('userData.username').valid && signupForm.get('userData.username').touched"
              class="help-block">
              <span *ngIf="signupForm.get('userData.username').errors['nameIsForbidden']">This name is invalid!</span>
              <span *ngIf="signupForm.get('userData.username').errors['required']">This field is required!</span>

            </span>
          </div>
          <div class="form-group">
            <label for="email">email</label>
            <input
              type="text"
              id="email"
              formControlName="email"
              class="form-control">
            <span
              *ngIf="!signupForm.get('userData.email').valid && signupForm.get('userData.email').touched"
              class="help-block">Please enter a valid email!</span>
          </div>
        </div>
        <div class="radio" *ngFor="let gender of genders">
          <label>
            <input
              type="radio"
              formControlName="gender"
              [value]="gender">{{ gender }}
          </label>
        </div>
        <div formArrayName="hobbies">
          <h4>Your Hobbies</h4>
          <button
            class="btn btn-default"
            type="button"
            (click)="onAddHobby()">Add Hobby</button>
          <div
            class="form-group"
            *ngFor="let hobbyControl of signupForm.get('hobbies').controls; let i = index">
            <input type="text" class="form-control" [formControlName]="i">
          </div>
        </div>
        <span
          *ngIf="!signupForm.valid && signupForm.touched"
          class="help-block">Please enter valid data!</span>
        <button class="btn btn-primary" type="submit">Submit</button>
      </form>
    </div>
  </div>
</div>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  genders = ['male', 'female'];
  signupForm: FormGroup;
  forbiddenUsernames = ['Chris', 'Anna'];

  constructor() {}

  ngOnInit() {
    this.signupForm = new FormGroup({
      'userData': new FormGroup({
        'username': new FormControl(null, [Validators.required, this.forbiddenNames.bind(this)]),
        'email': new FormControl(null, [Validators.required, Validators.email], this.forbiddenEmails)
      }),
      'gender': new FormControl('male'),
      'hobbies': new FormArray([])
    });
    // this.signupForm.valueChanges.subscribe(
    //   (value) => console.log(value)
    // );
    this.signupForm.statusChanges.subscribe(
      (status) => console.log(status)
    );
    this.signupForm.setValue({
      'userData': {
        'username': 'Max',
        'email': 'max@test.com'
      },
      'gender': 'male',
      'hobbies': []
    });
    this.signupForm.patchValue({
      'userData': {
        'username': 'Anna',
      }
    });
  }

  onSubmit() {
    console.log(this.signupForm);
    this.signupForm.reset();
  }

  onAddHobby() {
    const control = new FormControl(null, Validators.required);
    (<FormArray>this.signupForm.get('hobbies')).push(control);
  }

  forbiddenNames(control: FormControl): {[s: string]: boolean} {
    if (this.forbiddenUsernames.indexOf(control.value) !== -1) {
      return {'nameIsForbidden': true};
    }
    return null;
  }

  forbiddenEmails(control: FormControl): Promise<any> | Observable<any> {
    const promise = new Promise<any>((resolve, reject) => {
      setTimeout(() => {
        if (control.value === 'test@test.com') {
          resolve({'emailIsForbidden': true});
        } else {
          resolve(null);
        }
      }, 1500);
    });
    return promise;
  }
}