@@ -1,14 +1,32 @@
|
|
1 |
@let c = bookForm.controls;
|
2 |
|
3 |
<form [formGroup]="bookForm" (ngSubmit)="submitForm()">
|
|
|
4 |
<label for="title">Title</label>
|
5 |
-
<input
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
|
7 |
<label for="subtitle">Subtitle</label>
|
8 |
<input id="subtitle" [formControl]="c.subtitle" />
|
9 |
|
|
|
10 |
<label for="isbn">ISBN</label>
|
11 |
-
<input
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
<fieldset>
|
14 |
<legend>Authors</legend>
|
@@ -29,5 +47,5 @@
|
|
29 |
<label for="imageUrl">Thumbnail URL</label>
|
30 |
<input type="url" id="imageUrl" [formControl]="c.imageUrl" />
|
31 |
|
32 |
-
<button type="submit">Save</button>
|
33 |
</form>
|
|
|
1 |
@let c = bookForm.controls;
|
2 |
|
3 |
<form [formGroup]="bookForm" (ngSubmit)="submitForm()">
|
4 |
+
@let titleInvalid = isInvalid(c.title);
|
5 |
<label for="title">Title</label>
|
6 |
+
<input
|
7 |
+
id="title"
|
8 |
+
[formControl]="c.title"
|
9 |
+
[attr.aria-describedby]="titleInvalid ? 'title-error' : null"
|
10 |
+
[attr.aria-invalid]="titleInvalid"
|
11 |
+
/>
|
12 |
+
@if (titleInvalid) {
|
13 |
+
<small id="title-error">The title is invalid.</small>
|
14 |
+
}
|
15 |
|
16 |
<label for="subtitle">Subtitle</label>
|
17 |
<input id="subtitle" [formControl]="c.subtitle" />
|
18 |
|
19 |
+
@let isbnInvalid = isInvalid(c.isbn);
|
20 |
<label for="isbn">ISBN</label>
|
21 |
+
<input
|
22 |
+
id="isbn"
|
23 |
+
[formControl]="c.isbn"
|
24 |
+
[attr.aria-describedby]="isbnInvalid ? 'isbn-error' : null"
|
25 |
+
[attr.aria-invalid]="isbnInvalid"
|
26 |
+
/>
|
27 |
+
@if (isbnInvalid) {
|
28 |
+
<small id="isbn-error">The ISBN is invalid.</small>
|
29 |
+
}
|
30 |
|
31 |
<fieldset>
|
32 |
<legend>Authors</legend>
|
|
|
47 |
<label for="imageUrl">Thumbnail URL</label>
|
48 |
<input type="url" id="imageUrl" [formControl]="c.imageUrl" />
|
49 |
|
50 |
+
<button type="submit" [disabled]="bookForm.invalid">Save</button>
|
51 |
</form>
|
@@ -1,5 +1,5 @@
|
|
1 |
import { Component, output } from '@angular/core';
|
2 |
-
import { FormArray, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
3 |
|
4 |
import { Book } from '../../shared/book';
|
5 |
|
@@ -13,9 +13,21 @@ export class BookForm {
|
|
13 |
readonly submitBook = output<Book>();
|
14 |
|
15 |
bookForm = new FormGroup({
|
16 |
-
isbn: new FormControl('', {
|
17 |
-
|
18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
description: new FormControl('', { nonNullable: true }),
|
20 |
authors: new FormArray([
|
21 |
new FormControl('', { nonNullable: true })
|
@@ -29,6 +41,13 @@ export class BookForm {
|
|
29 |
);
|
30 |
}
|
31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
submitForm() {
|
33 |
const formValue = this.bookForm.getRawValue();
|
34 |
const authors = formValue.authors.filter(author => !!author);
|
|
|
1 |
import { Component, output } from '@angular/core';
|
2 |
+
import { FormArray, FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
3 |
|
4 |
import { Book } from '../../shared/book';
|
5 |
|
|
|
13 |
readonly submitBook = output<Book>();
|
14 |
|
15 |
bookForm = new FormGroup({
|
16 |
+
isbn: new FormControl('', {
|
17 |
+
nonNullable: true,
|
18 |
+
validators: [
|
19 |
+
Validators.required,
|
20 |
+
Validators.minLength(13),
|
21 |
+
Validators.maxLength(13),
|
22 |
+
]
|
23 |
+
}),
|
24 |
+
title: new FormControl('', {
|
25 |
+
nonNullable: true,
|
26 |
+
validators: Validators.required,
|
27 |
+
}),
|
28 |
+
subtitle: new FormControl('', {
|
29 |
+
nonNullable: true
|
30 |
+
}),
|
31 |
description: new FormControl('', { nonNullable: true }),
|
32 |
authors: new FormArray([
|
33 |
new FormControl('', { nonNullable: true })
|
|
|
41 |
);
|
42 |
}
|
43 |
|
44 |
+
isInvalid(control: FormControl) {
|
45 |
+
if (!control.touched) {
|
46 |
+
return null;
|
47 |
+
}
|
48 |
+
return control.invalid && control.touched;
|
49 |
+
}
|
50 |
+
|
51 |
submitForm() {
|
52 |
const formValue = this.bookForm.getRawValue();
|
53 |
const authors = formValue.authors.filter(author => !!author);
|