07 mar 2017
5 min

ANGULAR 2 Validation Service

Cześć po 2 tygodniowej przerwie! W dzisiejszym artykule VALIDATION SERVICE – usprawniamy wyświetlanie errorów. W poprzednich artykułach pokazałem jak wyświetlać błędy walidacji na widoku. Wykonywałem to w następujący sposób:

<span *ngIf="modelForm.controls['firstname'].dirty && modelForm.controls['firstname'].errors?.startsWith">
 Must start with {{ modelForm.controls['firstname'].errors?.startsWith }}
</span>

<span *ngIf="modelForm.controls.positions.controls[i].dirty && modelForm.controls['positions'].controls[i].errors?.oneRequired">
 At least one field is required
</span>

Jeśli powyższy kod nie jest dla Ciebie jasny, zalecam zapoznanie się z I częścią artykułu o Reactive Forms, a najlepiej przeczytanie wszystkich części dotyczących Reactive Forms.

A teraz wyobraź sobie, że masz 10 inputów, w tym różne typy errorów (Required, minLength, maxLength, pattern etc). Zaczyna pachnieć spaghetti code? O tak…

Zdecydowanie będzie lepiej, jeśli nasze powyższe dwa elementy span z errorami, wyglądałyby następująco:

<error-message [control]="modelForm.controls['lastname']"></error-message>

<error-message [control]="modelForm.controls.positions.controls[i]"></error-message>

Żadnych dirty, logiki, tekstu, nazwy errora, wyłącznie referencja do obiektu = profit.

Pokażę, jak przygotować serwis oraz komponent, który zwróci nam odpowiedni typ błędu. Po co nam to?

  • wszystkie teksty errorów trzymamy w jednym obiekcie, w przypadku zmiany możemy za jednym ruchem zmienić teksty w całej aplikacji
  • czystsza templatka
  • szybsza walidacja formularzy, nie tracimy zbędnego czasu na rozpisywanie

Poniżej link do plunkera, który zawiera kod z dalszej części artykułu:

LIVE EXAMPLE

Powyższy live example, jest on kontynuacją poprzedniego plunkera dotyczącego custom validatorów. W tym artykule interesują nas wyłącznie pliki:

  • app/validation.service.ts
  • app/error-message.component.ts
  • app/error-message.component.html
  • app/model-driven-form.component.html

Czas do kodu!

Validation Serivce

Zaczniemy od przygotowania serwisu, który będzie zwracać nam odpowiedni error. Jest to klasa z jedną metodą statyczną, która przyjmuje dwa argumenty – klucz w obiekcie, który zwraca walidator, oraz opcjonalnie wartość walidatora.

(app/validation.service.ts)

export class ValidationService {
  static getValidationMessage(validator : string, validatorValue? : any) {
    const messages = {
      'required': 'This field is required',
      'oneRequired': 'At least one field is required',
      'minlength': `Min length is ${validatorValue.requiredLength} characters`,
      'startsWith': `This field must start with ${validatorValue}`,
      'digits': 'This field must be a digit'
    };

    return messages[validator];
  }
}

Istotne, aby nasze klucze w obiekcie messages, nazywały się dokładnie tak jak klucze w obiekcie zwracanym przez walidator. Do obiektu messages dodajemy wszystkie możliwe walidacje, których używamy. Walidatory digits, oneRequired, startsWith stworzyłem w poprzednim artykule.

Serwis gotowy. Czas na komponent, wyświetlający odpowiedni error na widoku.

Error Message Component

Nasz komponent jest mały i prosty. Składa się wyłącznie z inputa i jednego gettera. Input() będzie odbierał referencję do obiektu, który reprezentuje kontrolkę lub grupę w formularzu (FormControl lub FormGroup).

Natomiast getter zwróci nam odpowiedni error z pomocą serwisu.

(app/error-message.component.ts)

import { Component, Input } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { ValidationService } from './validation.service';

@Component({
  moduleId: module.id,
  selector: 'error-message',
  templateUrl: './error-message.component.html'
})

export class ErrorMessageComponent {
  @Input() control: FormGroup | FormControl;

  get errorMessage() {
    for (let key in this.control.errors) {
      if (this.control.errors.hasOwnProperty(key) && this.control.dirty) {
        return ValidationService.getValidationMessage(key, this.control.errors[key]);
      }
    }

    return null;
  }
}

Jeszcze prosta templatka errora, którą oczywiście możesz ostylować wedle upodobań.

(app/error-message.component.html)

<div *ngIf="errorMessage !== null" class="error-container">
 <span class="error-text">{{ errorMessage }}</span>
</div>

Oraz użycie na widoku:

(app/model-driven-form.component.html)

<input class="form-control" name="lastname" formControlName="lastname">
<error-message [control]="modelForm.controls['lastname']"></error-message>

Jak widzimy, w data-bound [control], przekazujemy wyłącznie referencję do danej kontrolki / grupy. Możesz również sparametryzować error-message komponent i np decydować czy dirty / touched / pristine występuje w danej walidacji.

Wyświetlanie errorów nigdy nie było przyjemniejsze!:-) Link do plunkera:

LIVE EXAMPLE

Podziel się artykułem

Zapisz się na nasz newsletter

Dołącz do community Angular.love i bądź na bieżąco z trendami.