In der Welt von Angular sind Formulare für die Benutzerinteraktion unerlässlich, unabhängig davon, ob Sie eine einfache Anmeldeseite oder eine komplexere Benutzerprofiloberfläche erstellen. Angular bietet traditionell zwei Hauptansätze: vorlagengesteuerte Formulare und reaktive Formulare. In meiner vorherigen Serie über Angular Reactive Forms habe ich untersucht, wie man die Leistungsfähigkeit reaktiver Formulare nutzen kann, um komplexe Logik zu verwalten, dynamische Formulare zu erstellen und benutzerdefinierte Formularsteuerelemente zu erstellen.
Ein neues Tool zur Verwaltung der Reaktivität – Signale – wurde in Version 16 von Angular eingeführt und steht seitdem im Fokus der Angular-Betreuer und wird mit Version 17 stabil. Mit Signalen können Sie Zustandsänderungen verarbeiten Deklarativ bietet es eine spannende Alternative, die die Einfachheit vorlagengesteuerter Formulare mit der robusten Reaktivität reaktiver Formulare kombiniert. In diesem Artikel wird untersucht, wie Signale sowohl einfachen als auch komplexen Formen in Angular Reaktivität verleihen können.
Bevor wir uns mit dem Thema der Verbesserung vorlagengesteuerter Formulare mit Signalen befassen, lassen Sie uns kurz die traditionellen Formularansätze von Angular zusammenfassen:
Vorlagengesteuerte Formulare: Direkt in der HTML-Vorlage mithilfe von Anweisungen wie ngModel definiert, sind diese Formulare einfach einzurichten und ideal für einfache Formulare. Allerdings bieten sie möglicherweise nicht die feinkörnige Kontrolle, die für komplexere Szenarien erforderlich ist.
Hier ist ein Minimalbeispiel für ein vorlagengesteuertes Formular:
<form (ngSubmit)="onSubmit()"> <label for="name">Name:</label> <input> </li> </ol> <pre class="brush:php;toolbar:false">```typescript import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent { name = ''; onSubmit() { console.log(this.name); } } ```
Reaktive Formulare: Programmgesteuert in der Komponentenklasse mithilfe der Angular-Klassen FormGroup, FormControl und FormArray verwaltet; Reaktive Formulare bieten eine detaillierte Kontrolle über den Formularstatus und die Validierung. Dieser Ansatz eignet sich gut für komplexe Formen, wie ich in meinen vorherigen Artikeln zu Angular Reactive Forms besprochen habe.
Und hier ist ein minimales Beispiel einer reaktiven Form:
import { Component } from '@angular/core'; import { FormGroup, FormControl } from '@angular/forms'; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent { form = new FormGroup({ name: new FormControl('') }); onSubmit() { console.log(this.form.value); } }
```html <form [formGroup]="form" (ngSubmit)="onSubmit()"> <label for="name">Name:</label> <input> <h2> Introducing Signals as a New Way to Handle Form Reactivity </h2> <p>With the release of Angular 16, signals have emerged as a new way to manage reactivity. Signals provide a declarative approach to state management, making your code more predictable and easier to understand. When applied to forms, signals can enhance the simplicity of template-driven forms while offering the reactivity and control typically associated with reactive forms.</p> <p>Let’s explore how signals can be used in both simple and complex form scenarios.</p> <h3> Example 1: A Simple Template-Driven Form with Signals </h3> <p>Consider a basic login form. Typically, this would be implemented using template-driven forms like this:<br> </p> <pre class="brush:php;toolbar:false"><!-- login.component.html --> <form name="form" (ngSubmit)="onSubmit()"> <label for="email">E-mail</label> <input type="email"> <pre class="brush:php;toolbar:false">// login.component.ts import { Component } from "@angular/core"; @Component({ selector: "app-login", templateUrl: "./login.component.html", }) export class LoginComponent { public email: string = ""; public password: string = ""; onSubmit() { console.log("Form submitted", { email: this.email, password: this.password }); } }
Dieser Ansatz funktioniert gut für einfache Formen, aber durch die Einführung von Signalen können wir die Einfachheit beibehalten und gleichzeitig reaktive Fähigkeiten hinzufügen:
// login.component.ts import { Component, computed, signal } from "@angular/core"; import { FormsModule } from "@angular/forms"; @Component({ selector: "app-login", standalone: true, templateUrl: "./login.component.html", imports: [FormsModule], }) export class LoginComponent { // Define signals for form fields public email = signal(""); public password = signal(""); // Define a computed signal for the form value public formValue = computed(() => { return { email: this.email(), password: this.password(), }; }); public isFormValid = computed(() => { return this.email().length > 0 && this.password().length > 0; }); onSubmit() { console.log("Form submitted", this.formValue()); } }
<!-- login.component.html --> <form name="form" (ngSubmit)="onSubmit()"> <label for="email">E-mail</label> <input type="email"> <p>In this example, the form fields are defined as signals, allowing for reactive updates whenever the form state changes. The formValue signal provides a computed value that reflects the current state of the form. This approach offers a more declarative way to manage form state and reactivity, combining the simplicity of template-driven forms with the power of signals.</p> <p>You may be tempted to define the form directly as an object inside a signal. While such an approach may seem more concise, typing into the individual fields does not dispatch reactivity updates, which is usually a deal breaker. Here’s an example StackBlitz with a component suffering from such an issue:</p> <p>Therefore, if you'd like to react to changes in the form fields, it's better to define each field as a separate signal. By defining each form field as a separate signal, you ensure that changes to individual fields trigger reactivity updates correctly. </p> <h3> Example 2: A Complex Form with Signals </h3> <p>You may see little benefit in using signals for simple forms like the login form above, but they truly shine when handling more complex forms. Let's explore a more intricate scenario - a user profile form that includes fields like firstName, lastName, email, phoneNumbers, and address. The phoneNumbers field is dynamic, allowing users to add or remove phone numbers as needed.</p> <p>Here's how this form might be defined using signals:<br> </p> <pre class="brush:php;toolbar:false">// user-profile.component.ts import { JsonPipe } from "@angular/common"; import { Component, computed, signal } from "@angular/core"; import { FormsModule, Validators } from "@angular/forms"; @Component({ standalone: true, selector: "app-user-profile", templateUrl: "./user-profile.component.html", styleUrls: ["./user-profile.component.scss"], imports: [FormsModule, JsonPipe], }) export class UserProfileComponent { public firstName = signal(""); public lastName = signal(""); public email = signal(""); // We need to use a signal for the phone numbers, so we get reactivity when typing in the input fields public phoneNumbers = signal([signal("")]); public street = signal(""); public city = signal(""); public state = signal(""); public zip = signal(""); public formValue = computed(() => { return { firstName: this.firstName(), lastName: this.lastName(), email: this.email(), // We need to do a little mapping here, so we get the actual value for the phone numbers phoneNumbers: this.phoneNumbers().map((phoneNumber) => phoneNumber()), address: { street: this.street(), city: this.city(), state: this.state(), zip: this.zip(), }, }; }); public formValid = computed(() => { const { firstName, lastName, email, phoneNumbers, address } = this.formValue(); // Regex taken from the Angular email validator const EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; const isEmailFormatValid = EMAIL_REGEXP.test(email); return ( firstName.length > 0 && lastName.length > 0 && email.length > 0 && isEmailFormatValid && phoneNumbers.length > 0 && // Check if all phone numbers are valid phoneNumbers.every((phoneNumber) => phoneNumber.length > 0) && address.street.length > 0 && address.city.length > 0 && address.state.length > 0 && address.zip.length > 0 ); }); addPhoneNumber() { this.phoneNumbers.update((phoneNumbers) => { phoneNumbers.push(signal("")); return [...phoneNumbers]; }); } removePhoneNumber(index: number) { this.phoneNumbers.update((phoneNumbers) => { phoneNumbers.splice(index, 1); return [...phoneNumbers]; }); } }
Beachten Sie, dass das Feld „phoneNumbers“ als Signal eines Arrays von Signalen definiert ist. Diese Struktur ermöglicht es uns, Änderungen an einzelnen Telefonnummern zu verfolgen und den Formularstatus reaktiv zu aktualisieren. Die Methoden „addPhoneNumber“ und „removePhoneNumber“ aktualisieren das phoneNumbers-Signalarray und lösen Reaktivitätsaktualisierungen im Formular aus.
<!-- user-profile.component.html --> <Formular> <blockquote> <p>In der Vorlage verwenden wir das Signalarray phoneNumbers, um die Eingabefelder für Telefonnummern dynamisch darzustellen. Mit den Methoden „addPhoneNumber“ und „removePhoneNumber“ können Benutzer Telefonnummern reaktiv hinzufügen oder entfernen und so den Formularstatus aktualisieren. Beachten Sie die Verwendung der Track-Funktion, die notwendig ist, um sicherzustellen, dass die ngFor-Direktive Änderungen am phoneNumbers-Array korrekt verfolgt.</p> </blockquote> <p>Hier ist eine StackBlitz-Demo des komplexen Formularbeispiels, mit der Sie herumspielen können:</p> <h3> Formulare mit Signalen validieren </h3> <p>Die Validierung ist für jedes Formular von entscheidender Bedeutung und stellt sicher, dass die Benutzereingabe vor der Übermittlung die erforderlichen Kriterien erfüllt. Mit Signalen kann die Validierung reaktiv und deklarativ erfolgen. Im obigen Beispiel für ein komplexes Formular haben wir ein berechnetes Signal namens formValid implementiert, das prüft, ob alle Felder bestimmte Validierungskriterien erfüllen.</p> <p>Die Validierungslogik kann leicht angepasst werden, um verschiedene Regeln zu berücksichtigen, z. B. die Prüfung auf gültige E-Mail-Formate oder die Sicherstellung, dass alle erforderlichen Felder ausgefüllt sind. Durch die Verwendung von Signalen zur Validierung können Sie besser wartbaren und testbaren Code erstellen, da die Validierungsregeln klar definiert sind und automatisch auf Änderungen in Formularfeldern reagieren. Es kann sogar in ein separates Dienstprogramm abstrahiert werden, um es in verschiedenen Formen wiederverwendbar zu machen.</p> <p>Im komplexen Formularbeispiel stellt das formValid-Signal sicher, dass alle erforderlichen Felder ausgefüllt sind und validiert das E-Mail- und Telefonnummernformat.</p> <p>Dieser Validierungsansatz ist etwas einfach und muss besser mit den tatsächlichen Formularfeldern verknüpft werden. Während es für viele Anwendungsfälle funktioniert, möchten Sie in einigen Fällen möglicherweise warten, bis Angular explizite Unterstützung für „Signalformen“ hinzugefügt wird. Tim Deschryver begann mit der Implementierung einiger Abstraktionen rund um Signalformen, einschließlich Validierung, und schrieb einen Artikel darüber. Mal sehen, ob so etwas in Zukunft zu Angular hinzugefügt wird.</p> <h3> Warum Signale in Winkelformen verwenden? </h3> <p>Die Übernahme von Signalen in Angular bietet eine leistungsstarke neue Möglichkeit, den Formularstatus und die Reaktivität zu verwalten. Signale bieten einen flexiblen, deklarativen Ansatz, der die Handhabung komplexer Formulare vereinfachen kann, indem er die Stärken vorlagengesteuerter Formulare und reaktiver Formulare kombiniert. Hier sind einige wichtige Vorteile der Verwendung von Signalen in Winkelformen:</p> <ol> <li><p><strong>Deklarative Statusverwaltung</strong>: Mit Signalen können Sie Formularfelder und berechnete Werte deklarativ definieren, wodurch Ihr Code vorhersehbarer und leichter verständlich wird.</p></li> <li><p><strong>Reaktivität</strong>: Signale stellen reaktive Aktualisierungen für Formularfelder bereit und stellen sicher, dass Änderungen am Formularstatus automatisch Reaktivitätsaktualisierungen auslösen.</p></li> <li><p><strong>Granulare Kontrolle</strong>: Mit Signalen können Sie Formularfelder auf granularer Ebene definieren und so eine feinkörnige Kontrolle über den Formularstatus und die Validierung ermöglichen.</p></li> <li><p><strong>Dynamische Formulare</strong>: Signale können verwendet werden, um dynamische Formulare mit Feldern zu erstellen, die dynamisch hinzugefügt oder entfernt werden können, was eine flexible Möglichkeit zur Handhabung komplexer Formularszenarien bietet.</p></li> <li><p><strong>Einfachheit</strong>: Signale können eine einfachere und prägnantere Möglichkeit zur Verwaltung von Formularzuständen bieten als herkömmliche reaktive Formulare, wodurch das Erstellen und Verwalten komplexer Formulare einfacher wird.</p></li> </ol> <h3> Abschluss </h3> <p>In meinen vorherigen Artikeln haben wir die leistungsstarken Funktionen von Angular Reactive Forms untersucht, von der dynamischen Formularkonstruktion bis hin zu benutzerdefinierten Formularsteuerelementen. Mit der Einführung von Signalen verfügen Angular-Entwickler über ein neues Tool, das die Einfachheit vorlagengesteuerter Formulare mit der Reaktivität reaktiver Formulare verbindet.</p> <p>Während viele Anwendungsfälle reaktive Formulare erfordern, stellen Signale eine neue, leistungsstarke Alternative für die Verwaltung des Formularstatus in Angular-Anwendungen dar, die einen einfacheren, deklarativen Ansatz erfordern. Während sich Angular weiterentwickelt, können Sie durch das Experimentieren mit diesen neuen Funktionen besser wartbare und leistungsfähigere Anwendungen erstellen.</p> <p>Viel Spaß beim Codieren!</p>
Das obige ist der detaillierte Inhalt vonErforschung von Winkelformen: Eine neue Alternative mit Signalen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!