🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)
🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)

🔧 Programmierung 🕛 kürzlich 8 Min Lesezeit
0

Reactive Forms

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Reactive forms define the form structure and validation entirely in the component class using FormGroup and FormControl. The template only binds to these objects — no ngModel, no template variables for validation state.



Import ReactiveFormsModule in the component's imports array.









1. Setting up a reactive form



Define the form as a class field using FormGroup and FormControl:




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

@Component({
imports: [ReactiveFormsModule],
...
})
export class SignUpComponent {
form = new FormGroup({
email: new FormControl(''), // initial value
password: new FormControl(''),
});
}






Use [formGroup] on the <form> element and formControlName on each input:




CODE
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input formControlName="email" type="email" />
<input formControlName="password" type="password" />
<button type="submit">Submit</button>
</form>






To bind a single control outside of a [formGroup], use [formControl] directly:




CODE
<input [formControl]="form.controls.email" />






No form argument is needed in the submit handler — this.form is always available in the class:




CODE
onSubmit() {
console.log(this.form.value); // { email: '...', password: '...' }
console.log(this.form.controls.email.value); // '...'
}












2. Built-in validators



Pass validators in the FormControl options object using the Validators class from @angular/forms:




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

form = new FormGroup({
email: new FormControl('', {
validators: [Validators.required, Validators.email],
}),
password: new FormControl('', {
validators: [Validators.required, Validators.minLength(8)],
}),
});






Common built-in validators: required, email, minLength(n), maxLength(n), min(n), max(n), pattern(regex).






Displaying errors in the template



Use a getter to keep the template readable:




CODE
get emailInvalid() {
const ctrl = this.form.controls.email;
return ctrl.touched && ctrl.invalid;
}









CODE
<input formControlName="email" />
@if (emailInvalid) {
<p class="error">Enter a valid email address.</p>
}

@if (form.controls.password.errors?.['minlength']) {
<p class="error">Password must be at least 8 characters.</p>
}

<button type="submit" [disabled]="form.invalid">Submit</button>












3. Custom validators



A custom validator is a plain function that receives an AbstractControl and returns null if valid, or a ValidationErrors object if invalid. The object key becomes the error name.




CODE
import { AbstractControl, ValidationErrors } from '@angular/forms';

function mustContainQuestionMark(control: AbstractControl): ValidationErrors | null {
if (control.value?.includes('?')) {
return null; // valid
}
return { missingQuestionMark: true }; // invalid
}






Use it alongside built-in validators:




CODE
form = new FormGroup({
password: new FormControl('', {
validators: [Validators.required, mustContainQuestionMark],
}),
});









CODE
@if (form.controls.password.errors?.['missingQuestionMark']) {
<p class="error">Password must contain a question mark.</p>
}












4. Async validators



Async validators return an Observable<ValidationErrors | null> instead of a synchronous value. Angular sets the control's status to 'PENDING' while waiting and updates validity once the Observable emits.



A typical use case is checking whether an email is already registered:




CODE
import { Component, inject } from '@angular/core';
import { AbstractControl, ValidationErrors, FormGroup, FormControl, Validators } from '@angular/forms';
import { Observable, of, timer } from 'rxjs';
import { switchMap, map, catchError } from 'rxjs';
import { AuthService } from './auth.service';

@Component({ ... })
export class SignUpComponent {
private authService = inject(AuthService);

form = new FormGroup({
email: new FormControl('', {
validators: [Validators.required, Validators.email],
asyncValidators: [(control: AbstractControl): Observable<ValidationErrors | null> =>
timer(400).pipe(
switchMap(() => this.authService.isEmailTaken(control.value)),
map(taken => taken ? { emailTaken: true } : null),
catchError(() => of(null))
)
],
}),
});
}









CODE
<input formControlName="email" />

@if (form.controls.email.status === 'PENDING') {
<span>Checking availability…</span>
}
@if (form.controls.email.errors?.['emailTaken']) {
<p class="error">This email is already registered.</p>
}






How the debouncing works: timer(400) delays the API call by 400 ms. If the user types again before 400 ms elapse, Angular triggers a new validation cycle — unsubscribing from the previous Observable (which cancels the timer) and starting a fresh one. This naturally debounces the API call without any extra operator.



catchError(() => of(null)) ensures a network error does not permanently block submission — the field is treated as valid and the user can continue.









5. Reacting to value changes



form.valueChanges is an Observable that emits the full form value whenever any control changes. Subscribe to it in ngOnInit — the FormGroup is defined as a class field so it is ready before ngOnInit runs.



Use takeUntilDestroyed to clean up the subscription automatically when the component is destroyed:




CODE
import { Component, inject, OnInit } from '@angular/core';
import { DestroyRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { debounceTime, distinctUntilChanged } from 'rxjs';

@Component({ ... })
export class SignUpComponent implements OnInit {
private destroyRef = inject(DestroyRef);

form = new FormGroup({
email: new FormControl(''),
password: new FormControl(''),
});

ngOnInit() {
// whole form
this.form.valueChanges.pipe(
debounceTime(300),
distinctUntilChanged(),
takeUntilDestroyed(this.destroyRef)
).subscribe(value => {
console.log(value); // { email: '...', password: '...' }
});

// single control
this.form.controls.email.valueChanges.pipe(
debounceTime(300),
takeUntilDestroyed(this.destroyRef)
).subscribe(email => {
console.log('email changed:', email);
});
}
}






distinctUntilChanged() prevents re-processing when the emitted value is the same as the previous one — useful when you are triggering a search or API call.









6. Setting values programmatically



Use these methods to pre-fill a form (e.g. loading a user profile for editing) or to reset it after submission.




CODE
// setValue — must provide a value for every control; throws if any are missing
this.form.setValue({ email: '[email protected]', password: 'secret' });

// patchValue — updates only the controls you specify; ignores the rest
this.form.patchValue({ email: '[email protected]' }); // password is unchanged

// set a single control
this.form.controls.email.setValue('[email protected]');

// reset — clears values and resets state to pristine and untouched
this.form.reset();

// reset with specific initial values
this.form.reset({ email: '[email protected]', password: '' });































Method Requires all controls Resets state
setValue(obj) Yes — throws if any key is missing No
patchValue(obj) No — partial update is fine No
reset(obj?) No Yes — pristine, untouched


Prefer patchValue when pre-filling from an API response that may not include every field. Use reset() after a successful form submission to clear the form and its validation state.






7. Nested FormGroup



Nest a FormGroup inside another FormGroup to organise related fields. In the template, use formGroupName to scope the inner group.




CODE
form = new FormGroup({
name: new FormControl('', Validators.required),
address: new FormGroup({
street: new FormControl(''),
postcode: new FormControl(''),
}),
});









CODE
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input formControlName="name" placeholder="Full name" />

<fieldset formGroupName="address">
<input formControlName="street" placeholder="Street" />
<input formControlName="postcode" placeholder="Postcode" />
</fieldset>

<button type="submit">Submit</button>
</form>






form.value mirrors the nesting: { name: '...', address: { street: '...', postcode: '...' } }. Access a nested control with form.controls.address.controls.street.






8. FormArray



FormArray holds a dynamic list of controls whose length is not known at design time — for example, a list of email addresses the user can add or remove.




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

@Component({
imports: [ReactiveFormsModule],
...
})
export class ContactComponent {
form = new FormGroup({
emails: new FormArray([new FormControl('', Validators.email)]),
});

get emails() {
return this.form.controls.emails;
}

addEmail() {
this.emails.push(new FormControl('', Validators.email));
}

removeEmail(index: number) {
this.emails.removeAt(index);
}
}






Use formArrayName in the template and bind each control by its index with [formControlName]="$index":




CODE
<form [formGroup]="form">
<div formArrayName="emails">
@for (ctrl of emails.controls; track $index) {
<div>
<input [formControlName]="$index" type="email" placeholder="Email" />
<button type="button" (click)="removeEmail($index)">Remove</button>
</div>
}
</div>
<button type="button" (click)="addEmail()">Add email</button>
</form>






Key FormArray methods: push(control), removeAt(index), at(index), length.






9. FormGroup validators



A validator registered on the FormGroup receives the entire group as its AbstractControl, allowing comparison across fields. Register it in the second argument to FormGroup:




CODE
function passwordsMatch(group: AbstractControl): ValidationErrors | null {
const password = group.get('password')?.value;
const confirm = group.get('confirmPassword')?.value;
return password === confirm ? null : { passwordMismatch: true };
}

form = new FormGroup({
password: new FormControl('', [Validators.required, Validators.minLength(8)]),
confirmPassword: new FormControl('', Validators.required),
}, {
validators: [passwordsMatch],
});






The error lands on form.errors, not on any individual control:




CODE
<input formControlName="confirmPassword" type="password" placeholder="Confirm password" />
@if (form.errors?.['passwordMismatch'] && form.controls.confirmPassword.touched) {
<p class="error">Passwords do not match.</p>
}






Angular also adds aggregate state classes to the <form> element — ng-valid, ng-dirty, ng-touched, ng-pending, and ng-submitted — each reflecting the combined state across all controls.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
3 Quellen
GPT-6 Astra Release Today? OpenAI’s Next Major AI Model Is Almost Here
1 Quelle
Apple accuses OpenAI of destroying evidence as trade-secrets fight intensifies
1 Quelle
Major AI platforms go down in unprecedented simultaneous outage
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Reactive Forms

Thematisch verwandte Begriffe: Reactive, Forms · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...