Help me een aangepaste Angular-validator implementeren voor complexe formulier velden
description
Door het implementeren van een aangepaste validator kan ik ervoor zorgen dat mijn formulier velden aan specifieke criteria voldoen, waardoor de gegevensintegriteit en gebruikerservaring verbeteren door duidelijke foutmeldingen.
prompt
try_prompt
Help me bij het maken van een aangepaste Angular-validator die complexe validatiescenario's voor mijn formulier velden kan afhandelen. Leg uit hoe je de validatorfunctie ontwikkelt, ... more
generate_helper
...
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Natuurlijk! Hier is een overzicht en stapsgewijze uitleg om een aangepaste Angular-validator te maken, te integreren en te gebruiken voor complexe validaties, inclusief voorbeelden voor tekstvelden en foutmeldingen.
### 1. Ontwikkelen van de validatorfunctie
Een aangepaste validator in Angular is een functie die een `ValidatorFn` teruggeeft, oftewel een functie die een `AbstractControl` ontvangt en een `ValidationErrors | null` retourneert.
**Voorbeeld: Een validator die controleert of een tekstveld aan meerdere criteria voldoet**
```typescript
import { AbstractControl, ValidatorFn } from '@angular/forms';
export function complexeTekstValidator(): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
const waarde = control.value;
// Controleer of er een waarde is
if (!waarde || typeof waarde !== 'string') {
return { 'geenString': true };
}
// Voorbeeld validatie: minimaal 8 tekens
if (waarde.length < 8) {
return { 'minLengte': { requiredLength: 8, actualLength: waarde.length } };
}
// Voorbeeld validatie: bevat minimaal één hoofdletter
if (!/[A-Z]/.test(waarde)) {
return { 'hoofdletter': true };
}
// Voorbeeld validatie: bevat minimaal één cijfer
if (!/\d/.test(waarde)) {
return { 'cijfer': true };
}
// Als alle validaties slagen
return null;
};
}
```
### 2. Integratie in het formulier
Gebruik deze validator bij het opzetten van je formulier:
```typescript
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.mijnFormulier = this.fb.group({
wachtwoord: ['', [Validators.required, complexeTekstValidator()]],
});
}
```
### 3. Validatieregels voor tekst
Hier enkele voorbeelden van validatie-voorwaarden die je kunt toepassen:
- Minimaal aantal tekens
- Bevatten van hoofdletters, kleine letters, cijfers, speciale tekens
- Verboden woorden of patronen
- Uniciteit check (bijvoorbeeld via API)
### 4. Foutmeldingen voor de gebruiker
In de template kun je de foutmeldingen tonen volgens de validator keys:
```html
<input formControlName="wachtwoord" placeholder="Voer wachtwoord in" />
<div *ngIf="mijnFormulier.get('wachtwoord')?.touched && mijnFormulier.get('wachtwoord')?.invalid">
<small *ngIf="mijnFormulier.get('wachtwoord')?.errors?.geenString">Dit veld mag niet leeg zijn.</small>
<small *ngIf="mijnFormulier.get('wachtwoord')?.errors?.minLengte">
Wachtwoord moet minimaal {{mijnFormulier.get('wachtwoord')?.errors?.minLengte.requiredLength}} tekens bevatten.
</small>
<small *ngIf="mijnFormulier.get('wachtwoord')?.errors?.hoofdletter">Bevat minimaal één hoofdletter.</small>
<small *ngIf="mijnFormulier.get('wachtwoord')?.errors?.cijfer">Bevat minimaal één cijfer.</small>
</div>
```
### Samenvatting
- Maak een validatorfunctie die meerdere regels controleert.
- Voeg deze validator toe aan het formulier of specifiek veld.
- Gebruik de `errors` property om foutmeldingen te bepalen.
- Toon relevante foutmeldingen in de template voor een goede gebruikerservaring.
Wil je nog meer voorbeelden of hulp bij specifieke validatieregels?
provider: deepseek
model: deepseek-chat
Zeker! Ik help je graag bij het maken van een aangepaste Angular-validator. Hier is een complete uitleg in het Nederlands:
## 1. Aangepaste Validator Functie Ontwikkelen
### Basisstructuur van een Custom Validator
```typescript
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
// Voorbeeld 1: Validator voor e-mail met specifiek domein
export function emailDomeinValidator(domein: string): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
if (!control.value) {
return null; // Geen validatiefout als veld leeg is
}
const emailPattern = new RegExp(`^[a-zA-Z0-9._%+-]+@${domein}$`);
const isValid = emailPattern.test(control.value);
return isValid ? null : { emailDomein: { value: control.value, verwachtDomein: domein } };
};
}
// Voorbeeld 2: Validator voor wachtwoordsterkte
export function sterkWachtwoordValidator(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
if (!control.value) {
return null;
}
const waarde = control.value;
const fouten: string[] = [];
if (waarde.length < 8) {
fouten.push('minimaal 8 karakters');
}
if (!/(?=.*[a-z])/.test(waarde)) {
fouten.push('minimaal 1 kleine letter');
}
if (!/(?=.*[A-Z])/.test(waarde)) {
fouten.push('minimaal 1 hoofdletter');
}
if (!/(?=.*\d)/.test(waarde)) {
fouten.push('minimaal 1 cijfer');
}
if (!/(?=.*[@$!%*?&])/.test(waarde)) {
fouten.push('minimaal 1 speciaal teken');
}
return fouten.length === 0 ? null : {
zwakWachtwoord: {
ontbrekendeEisen: fouten
}
};
};
}
// Voorbeeld 3: Validator voor Nederlandse postcode
export function nederlandsePostcodeValidator(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
if (!control.value) {
return null;
}
// Formaat: 1234 AB (met of zonder spatie)
const postcodePattern = /^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/;
const isValid = postcodePattern.test(control.value);
return isValid ? null : { ongeldigePostcode: true };
};
}
```
## 2. Integratie met Formulieren
### Reactive Forms Integratie
```typescript
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import {
emailDomeinValidator,
sterkWachtwoordValidator,
nederlandsePostcodeValidator
} from './aangepaste-validators';
@Component({
selector: 'app-mijn-formulier',
template: `
<form [formGroup]="mijnFormulier" (ngSubmit)="onSubmit()">
<!-- Template komt later -->
</form>
`
})
export class MijnFormulierComponent {
mijnFormulier: FormGroup;
constructor(private fb: FormBuilder) {
this.mijnFormulier = this.fb.group({
email: ['', [
Validators.required,
Validators.email,
emailDomeinValidator('voorbeeld.nl')
]],
wachtwoord: ['', [
Validators.required,
sterkWachtwoordValidator()
]],
postcode: ['', [
Validators.required,
nederlandsePostcodeValidator()
]],
telefoon: ['', [
Validators.required,
this.telefoonValidator()
]]
});
}
// Inline validator voor telefoonnummer
private telefoonValidator(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
if (!control.value) {
return null;
}
const telefoonPattern = /^(\+31|0|0031)[1-9][0-9]{8}$/;
const isValid = telefoonPattern.test(control.value.replace(/\s/g, ''));
return isValid ? null : { ongeldigTelefoonnummer: true };
};
}
onSubmit() {
if (this.mijnFormulier.valid) {
console.log('Formulier is geldig:', this.mijnFormulier.value);
} else {
console.log('Formulier bevat fouten');
this.mijnFormulier.markAllAsTouched();
}
}
}
```
## 3. Template met Foutmeldingen
```html
<form [formGroup]="mijnFormulier" (ngSubmit)="onSubmit()" class="form-container">
<!-- E-mail veld -->
<div class="form-group">
<label for="email">E-mailadres *</label>
<input
id="email"
type="email"
formControlName="email"
placeholder="naam@voorbeeld.nl"
[class.is-invalid]="email.invalid && email.touched">
<div *ngIf="email.invalid && email.touched" class="error-messages">
<div *ngIf="email.errors?.['required']">E-mailadres is verplicht</div>
<div *ngIf="email.errors?.['email']">Voer een geldig e-mailadres in</div>
<div *ngIf="email.errors?.['emailDomein']">
E-mail moet eindigen op @{{ email.errors?.['emailDomein']?.verwachtDomein }}
</div>
</div>
</div>
<!-- Wachtwoord veld -->
<div class="form-group">
<label for="wachtwoord">Wachtwoord *</label>
<input
id="wachtwoord"
type="password"
formControlName="wachtwoord"
[class.is-invalid]="wachtwoord.invalid && wachtwoord.touched">
<div *ngIf="wachtwoord.invalid && wachtwoord.touched" class="error-messages">
<div *ngIf="wachtwoord.errors?.['required']">Wachtwoord is verplicht</div>
<div *ngIf="wachtwoord.errors?.['zwakWachtwoord']">
Wachtwoord voldoet niet aan de eisen:
<ul>
<li *ngFor="let eis of wachtwoord.errors?.['zwakWachtwoord']?.ontbrekendeEisen">
{{ eis }}
</li>
</ul>
</div>
</div>
</div>
<!-- Postcode veld -->
<div class="form-group">
<label for="postcode">Postcode *</label>
<input
id="postcode"
type="text"
formControlName="postcode"
placeholder="1234 AB"
[class.is-invalid]="postcode.invalid && postcode.touched">
<div *ngIf="postcode.invalid && postcode.touched" class="error-messages">
<div *ngIf="postcode.errors?.['required']">Postcode is verplicht</div>
<div *ngIf="postcode.errors?.['ongeldigePostcode']">
Voer een geldige Nederlandse postcode in (bijv. 1234 AB)
</div>
</div>
</div>
<!-- Telefoon veld -->
<div class="form-group">
<label for="telefoon">Telefoonnummer *</label>
<input
id="telefoon"
type="tel"
formControlName="telefoon"
placeholder="0612345678"
[class.is-invalid]="telefoon.invalid && telefoon.touched">
<div *ngIf="telefoon.invalid && telefoon.touched" class="error-messages">
<div *ngIf="telefoon.errors?.['required']">Telefoonnummer is verplicht</div>
<div *ngIf="telefoon.errors?.['ongeldigTelefoonnummer']">
Voer een geldig Nederlands telefoonnummer in
</div>
</div>
</div>
<button
type="submit"
[disabled]="mijnFormulier.invalid"
class="submit-btn">
Versturen
</button>
</form>
```
## 4. Getter Methods voor Gemakkelijke Toegang
```typescript
// In je component class
get email() {
return this.mijnFormulier.get('email');
}
get wachtwoord() {
return this.mijnFormulier.get('wachtwoord');
}
get postcode() {
return this.mijnFormulier.get('postcode');
}
get telefoon() {
return this.mijnFormulier.get('telefoon');
}
```
## 5. CSS voor Styling
```css
.form-container {
max-width: 500px;
margin: 0 auto;
padding: 20px;
}
.form-group {
margin-bottom: 1rem;
}
label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
}
input {
width: 100%;
padding: 0.5rem;
border: 1px solid #ccc;
border-radius: 4px;
}
input.is-invalid {
border-color: #dc3545;
}
.error-messages {
color: #dc3545;
font-size: 0.875rem;
margin-top: 0.25rem;
}
.error-messages ul {
margin: 0.25rem 0;
padding-left: 1rem;
}
.submit-btn {
background-color: #007bff;
color: white;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 4px;
cursor: pointer;
}
.submit-btn:disabled {
background-color: #6c757d;
cursor: not-allowed;
}
```
## 6. Geavanceerde Validator: Cross-Field Validatie
```typescript
// Validator die twee velden vergelijkt (bijv. wachtwoord bevestiging)
export function vergelijkVeldenValidator(
veld1Naam: string,
veld2Naam: string
): ValidatorFn {
return (formGroup: AbstractControl): ValidationErrors | null => {
const veld1 = formGroup.get(veld1Naam);
const veld2 = formGroup.get(veld2Naam);
if (!veld1 || !veld2) {
return null;
}
if (veld2.errors && !veld2.errors['veldenKomenNietOvereen']) {
return null;
}
if (veld1.value !== veld2.value) {
veld2.setErrors({ veldenKomenNietOvereen: true });
} else {
veld2.setErrors(null);
}
return null;
};
}
```
## Belangrijke Tips:
1. **Async Validators**: Gebruik `AsyncValidatorFn` voor server-side validatie
2. **Performance**: Valideer alleen wanneer nodig met `updateOn` optie
3. **Hergebruik**: Maak validators generiek met parameters
4. **Testing**: Schrijf unit tests voor je custom validators
5. **Accessibility**: Gebruik ARIA-attributen voor schermlezers
Deze aanpak geeft je een robuust validatiesysteem dat eenvoudig uit te breiden is voor complexe scenario's!

