Differenzansicht 11-forms
im Vergleich zu 10-pipes

← Zurück zur Ãœbersicht | Demo | Quelltext auf GitHub
src/app/app.ng.html CHANGED
@@ -9,6 +9,10 @@
9
  <a routerLink="/books" routerLinkActive="active"
10
  ariaCurrentWhenActive="page">Books</a>
11
  </li>
 
 
 
 
12
  </ul>
13
  </nav>
14
  <router-outlet />
 
9
  <a routerLink="/books" routerLinkActive="active"
10
  ariaCurrentWhenActive="page">Books</a>
11
  </li>
12
+ <li>
13
+ <a routerLink="/admin" routerLinkActive="active"
14
+ ariaCurrentWhenActive="page">Admin</a>
15
+ </li>
16
  </ul>
17
  </nav>
18
  <router-outlet />
src/app/app.routes.ts CHANGED
@@ -2,9 +2,11 @@ import { Routes } from '@angular/router';
2
 
3
  import { HomePage } from './home-page/home-page';
4
  import { booksPortalRoutes } from './books-portal/books-portal.routes';
 
5
 
6
  export const routes: Routes = [
7
  { path: '', redirectTo: 'home', pathMatch: 'full' },
8
  { path: 'home', component: HomePage, title: 'BookMonkey' },
9
- ...booksPortalRoutes
 
10
  ];
 
2
 
3
  import { HomePage } from './home-page/home-page';
4
  import { booksPortalRoutes } from './books-portal/books-portal.routes';
5
+ import { booksAdminRoutes } from './books-admin/books-admin.routes';
6
 
7
  export const routes: Routes = [
8
  { path: '', redirectTo: 'home', pathMatch: 'full' },
9
  { path: 'home', component: HomePage, title: 'BookMonkey' },
10
+ ...booksPortalRoutes,
11
+ ...booksAdminRoutes
12
  ];
src/app/books-admin/book-create/book-create.ng.html ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ <h1>Create book</h1>
2
+ <app-book-form (submitBook)="create($event)" />
src/app/books-admin/book-create/book-create.ts ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Component, inject } from '@angular/core';
2
+ import { Router } from '@angular/router';
3
+
4
+ import { BookForm } from '../book-form/book-form';
5
+ import { BookStore } from '../../shared/book-store';
6
+ import { Book } from '../../shared/book';
7
+
8
+ @Component({
9
+ selector: 'app-book-create',
10
+ imports: [BookForm],
11
+ templateUrl: './book-create.ng.html',
12
+ styleUrl: './book-create.scss'
13
+ })
14
+ export class BookCreate {
15
+ #store = inject(BookStore);
16
+ #router = inject(Router);
17
+
18
+ create(book: Book) {
19
+ this.#store.createBook(book).subscribe(createdBook => {
20
+ this.#router.navigate(['/books', 'details', createdBook.isbn]);
21
+ });
22
+ }
23
+ }
src/app/books-admin/book-form/book-form.ng.html ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @let c = bookForm.controls;
2
+
3
+ <form [formGroup]="bookForm" (ngSubmit)="submitForm()">
4
+ <label for="title">Title</label>
5
+ <input id="title" [formControl]="c.title" />
6
+
7
+ <label for="subtitle">Subtitle</label>
8
+ <input id="subtitle" [formControl]="c.subtitle" />
9
+
10
+ <label for="isbn">ISBN</label>
11
+ <input id="isbn" [formControl]="c.isbn" />
12
+
13
+ <fieldset>
14
+ <legend>Authors</legend>
15
+ <button type="button" (click)="addAuthorControl()">Add Author</button>
16
+ <div role="group">
17
+ @for (authorControl of c.authors.controls; track $index) {
18
+ <input
19
+ [attr.aria-label]="'Author ' + $index"
20
+ [formControl]="authorControl"
21
+ />
22
+ }
23
+ </div>
24
+ </fieldset>
25
+
26
+ <label for="description">Description</label>
27
+ <textarea id="description" [formControl]="c.description"></textarea>
28
+
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>
src/app/books-admin/book-form/book-form.ts ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Component, output } from '@angular/core';
2
+ import { FormArray, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
3
+
4
+ import { Book } from '../../shared/book';
5
+
6
+ @Component({
7
+ selector: 'app-book-form',
8
+ imports: [ReactiveFormsModule],
9
+ templateUrl: './book-form.ng.html',
10
+ styleUrl: './book-form.scss'
11
+ })
12
+ export class BookForm {
13
+ readonly submitBook = output<Book>();
14
+
15
+ bookForm = new FormGroup({
16
+ isbn: new FormControl('', { nonNullable: true }),
17
+ title: new FormControl('', { nonNullable: true }),
18
+ subtitle: new FormControl('', { nonNullable: true }),
19
+ description: new FormControl('', { nonNullable: true }),
20
+ authors: new FormArray([
21
+ new FormControl('', { nonNullable: true })
22
+ ]),
23
+ imageUrl: new FormControl('', { nonNullable: true })
24
+ });
25
+
26
+ addAuthorControl() {
27
+ this.bookForm.controls.authors.push(
28
+ new FormControl('', { nonNullable: true })
29
+ );
30
+ }
31
+
32
+ submitForm() {
33
+ const formValue = this.bookForm.getRawValue();
34
+ const authors = formValue.authors.filter(author => !!author);
35
+
36
+ const newBook: Book = {
37
+ ...formValue,
38
+ authors,
39
+ createdAt: new Date().toISOString()
40
+ };
41
+
42
+ this.submitBook.emit(newBook);
43
+ }
44
+ }
src/app/books-admin/books-admin.routes.ts ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ import { Routes } from '@angular/router';
2
+
3
+ import { BookCreate } from './book-create/book-create';
4
+
5
+ export const booksAdminRoutes: Routes = [
6
+ { path: 'admin', redirectTo: 'admin/create' },
7
+ { path: 'admin/create', component: BookCreate, title: 'Create Book' }
8
+ ];
src/app/shared/book-store.ts CHANGED
@@ -27,4 +27,8 @@ export class BookStore {
27
  deleteBook(isbn: string): Observable<unknown> {
28
  return this.#http.delete(`${this.#apiUrl}/books/${isbn}`);
29
  }
 
 
 
 
30
  }
 
27
  deleteBook(isbn: string): Observable<unknown> {
28
  return this.#http.delete(`${this.#apiUrl}/books/${isbn}`);
29
  }
30
+
31
+ createBook(book: Book): Observable<Book> {
32
+ return this.#http.post<Book>(`${this.#apiUrl}/books`, book);
33
+ }
34
  }