GEDOPLAN

Angular – eigene ReactiveForm Komponenten

Alle
cake 1587096 640 1

In größeren Projekten werden wir relativ schnell den Punkt erreichen in dem sich der ein oder andere Entwickler denkt: „Moment das hatten wir doch schon mal“. Wenn noch nicht geschehen ist das der Zeitpunkt um für den so identifizierten Bereich / Funktion eine eigene Komponente aus zu bilden. Wenn es sich dabei um ein Form-Element handelt mag es zuerst einmal nicht so offensichtlich sein wie man das am besten bewerkstelligt…

cake 1587096 640 1

Nehmen wir ein einfaches konkretes Beispiel: in unserer Anwendung haben wir eine Auswahlbox von Benutzern durch die z.B. eine Aufgabe, ein Projekt etc. zugeordnet werden soll. Diese Auswahl von Benutzern wird nun an verschiedenen Stellen der Anwendung benötigt. Also entwickeln wir eine eigenen Komponente, was dank Angular-CLI ja auch ein Kinderspiel ist:

ng generate component UserSelector

So einfach ist es in diesem Beispiel jedoch erst einmal nicht. Das Ziel soll es ja sein unsere Komponente als Teil eines Formulars zu verwenden und eine Deklaration analog zu den Standard-HTML Elementen zu erreichen:

<form [formGroup]="form">
  <label for="user">Benutzer: </label>
  <app-user-selector formControlName="userId" id="user"></app-user-selector>
  <label for="comment">Kommentar: </label>
  <input type="text" id="comment" formControlName="comment"/>
</form>

app.component.html > Verwendung unserer Komponente

wir wollen hier einen ReactiveForm-Ansatz verfolgen bei dem die Registrierung von Datenmodel und Validatoren in der Komponentenklasse geschieht, dazu wird hier der Name des Controls mittels ‚formControlName‘ eingesetzt. Die Alternative wäre der Einsatz von „ngModel“

In unserem Projekt setzen wir PrimeNG als Komponentenbibliothek ein, unsere UserSelector Komponente wird also lediglich eine Art Wrapper, hier das Template:

<span [formGroup]="form">
  <p-dropdown
    [options]="users"
    optionLabel="name"
    class="form-control"
    [autoDisplayFirst]="false"
    dataKey="id"
    formControlName="value"
  ></p-dropdown>
</span>

user-selector-component.html > Template unserer Komponente

wir verwenden hier eine PrimeNG Komponente ‚p-dropdown‘. Für unsere eigene Komponente spannend ist hier die Erzeugung einer eigenen FormGroup innerhalb unserer Komponente, das ermöglicht uns die PrimeNG Komponente innerhalb „ganz normal“ mit unserer Komponenten-Klasse zu verbinden

import { Component, OnInit, forwardRef } from '@angular/core';
import { FormGroup, ControlValueAccessor, NG_VALUE_ACCESSOR, FormBuilder } from '@angular/forms';
import { DemoService } from '../demo.service';

// 1
@Component({
  selector: 'app-user-selector',
  templateUrl: './user-selector.component.html',
  styleUrls: ['./user-selector.component.css'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => UserSelectorComponent),
      multi: true
    }
  ]
})
//2
export class UserSelectorComponent implements ControlValueAccessor {
  users: any[];

  form: FormGroup;

  //3
  constructor(private service: DemoService, builder: FormBuilder) {
    service.getAll().subscribe(r => (this.users = r));

    this.form = builder.group({
      value: ['']
    });
    //4
    this.form.controls.value.valueChanges.subscribe(c => {
      this.onChange(c.id);
    });
  }

  //5
  writeValue(obj: number): void {
    if (obj) {
      const value = this.users.find(e => e.id == obj);
      if (value) this.form.patchValue({ value });
    }
  }

  //6
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  onChange: any = () => {};
  onTouched: any = () => {};
}

user-selector-component.ts > Komponentenklasse

1. die Metadaten für unsere Komponente. Neu an dieser Stelle ist die Registrierung unserer Komponente als Value-Accessor über das Provider Array, sehr einfach ausgedrückt ist dieses Deklaration bei jeder dieser Komponenten technisch bedingt genau so zu deklarieren ( sehr spannende Angular-Hintergrund-Themen zu dieser Deklaration: ‚Multi Providers‘ und ‚forwardRef‘ )

2. wir Implementieren das Interface ControlValueAccessor

3. Konstruktor. Neben einem Demo-Service ( der uns die Daten für unsere Liste ermittelt), lassen wir uns auch den FormBuilder von Anuglar injizieren um die FormGroup auf zu bauen

4. hier wird es spannender: wir registrieren einen Change-Listener an unserer internen FormControl ( die PrimeNG Dropdown-Liste ). Wenn der User hier eine Änderungen vornimmt wollen wir dieses Event „weiter geben“ und den Verwender unserer Komponente informieren, dazu wird die Methode onChange ( Interface ) verwendet. ( In unserem Beispiel nehmen wir hier auch eine Umwandlung vor: unserer DropDown-Liste liefert ein komplexes User-Objekt, in unserer Anwendung, also in den anderen fachlichen Objekten verwenden wir lediglich die Id.

5. writeValue ( Interface ) ist die Methode welche aufgerufen wir um ein Objekt welches aus dem Model kommt in der UI darzustellen, also beim Rendern oder bei Änderungen der Form. Wir bekommen an dieser Stelle die Id des bereits selektierten Benutzers, anhand dessen wir das komplexe User-Objekt aus unserem Array ermitteln und unser internes Formular damit aktualisieren.

6. Interface Methoden um die Registrierungen von EventListenern zu ermöglichen

Das war’s damit haben wir eine Komponente welche ganz einfach in unseren Formularen eingesetzt werden kann. Auf diese Weise lassen sich natürlich auch gänzlich eigene Komponenten ( ohne PrimeNG ) implementieren oder wesentlich komplexere wiederverwendbare Komponenten.

Noch mal gucken? > GITHUB

Autor

Diesen Artikel teilen

LinkedIn
Xing

Gibt es noch Fragen?

Fragen beantworten wir sehr gerne! Schreibe uns einfach per Kontaktformular.

Schulungen mit der selben Kategorie:

Blogkategorie: Alle
Es wurden keine Ergebnisse gefunden.

weitere Artikel

Kontakt

Brauchen Sie eine individuelle IT-Schulung, eine fundierte Beratung oder eine individuelle Softwareentwicklung? Dann sind Sie hier genau richtig!

Tim Neumann

Geschäftsleitung

GEDOPLAN GmbH
Stieghorster Straße 60
33605 Bielefeld

GEDOPLAN GmbH
Kantstraße 164
10623 Berlin

    Kontakt

    Tim Neumann

    Geschäftsleitung

    GEDOPLAN GmbH
    Stieghorster Straße 60
    33605 Bielefeld

    GEDOPLAN GmbH
    Kantstraße 164
    10623 Berlin

    Brauchen Sie eine individuelle IT-Schulung, eine fundierte Beratung oder eine individuelle Softwareentwicklung? Dann sind Sie hier genau richtig!