*ngIf
will automatically recompute the validity of the form when shown.
// app/conditional-validation/profile.ts
export interface Profile {
id: number;
name: string;
wantsPet: boolean;
address?: string;
petName?: string;
}
<!-- app/conditional-validation/profile-form-template/profile-form-template.component.html -->
<h1>Profile Form (template-based)</h1>
<mat-card>
<form (ngSubmit)="submit()" #profileForm="ngForm">
<mat-form-field>
<mat-label>Name</mat-label>
<input
matInput
required
name="name"
[(ngModel)]="profile.name"
#name="ngModel"
/>
<mat-error *ngIf="name.errors?.required"
>You must enter a value</mat-error
>
</mat-form-field>
<div>
<mat-slide-toggle name="wantsPet" [(ngModel)]="profile.wantsPet"
>I would like to adopt a new pet</mat-slide-toggle
>
</div>
<mat-form-field>
<mat-label>Address</mat-label>
<input
matInput
[required]="profile.wantsPet"
name="address"
[(ngModel)]="profile.address"
#address="ngModel"
/>
<mat-error *ngIf="address.errors?.required"
>You must enter a value</mat-error
>
</mat-form-field>
<div>
<mat-slide-toggle name="hasPet" [(ngModel)]="hasPet"
>I currently have a pet</mat-slide-toggle
>
</div>
<mat-form-field *ngIf="hasPet">
<mat-label>Pet name</mat-label>
<input
matInput
required
name="petName"
[(ngModel)]="profile.petName"
#petName="ngModel"
/>
<mat-error *ngIf="petName.errors?.required"
>You must enter a value</mat-error
>
</mat-form-field>
<div class="form-buttons">
<button
mat-raised-button
type="submit"
color="primary"
[disabled]="loading || !profileForm.form.valid"
>
Submit
</button>
</div>
</form>
</mat-card>
<h2>Profile (JSON)</h2>
<pre
>{{ profile | json }}
</pre>
// app/conditional-validation/profile-form-template/profile-form-template.component.ts
import { Component } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { finalize } from 'rxjs/operators';
import { Profile } from '../profile';
import { ProfileService } from '../profile.service';
@Component({
selector: 'app-profile-form-template',
templateUrl: './profile-form-template.component.html',
})
export class ProfileFormTemplateComponent {
readonly profile: Profile = {
id: 0,
name: '',
wantsPet: false,
};
hasPet = false;
loading = false;
constructor(
private readonly profileService: ProfileService,
private readonly snackBar: MatSnackBar
) {}
submit(): void {
if (!this.hasPet) {
this.profile.petName = undefined;
}
this.loading = true;
this.profileService
.save(this.profile)
.pipe(finalize(() => (this.loading = false)))
.subscribe(({ id }) => {
this.snackBar.open(`Profile saved with ID #${id}`, 'Close');
});
}
}
// app/conditional-validation/profile.service.ts
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { delay } from 'rxjs/operators';
import { Profile } from './profile';
export interface ProfileSaveResponse {
id: number;
}
@Injectable({
providedIn: 'root',
})
export class ProfileService {
save(profile: Profile): Observable<ProfileSaveResponse> {
console.log('Save:', profile);
return of({
id: 1,
}).pipe(delay(1000));
}
}