BookMonkey 3 Diff

Files changed (11) hide show
  1. tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/app-routing.module.ts +5 -0
  2. tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/app.module.ts +5 -3
  3. tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/book-details/book-details.component.html +4 -0
  4. tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/book-form/book-form.component.html +42 -50
  5. tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/book-form/book-form.component.ts +95 -13
  6. tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/create-book/create-book.component.html +2 -2
  7. tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/create-book/create-book.component.ts +1 -0
  8. tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/edit-book/edit-book.component.html +8 -0
  9. tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/edit-book/edit-book.component.ts +37 -0
  10. tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/shared/book-factory.ts +0 -15
  11. tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/shared/book-store.service.ts +10 -0
tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/app-routing.module.ts RENAMED
@@ -5,6 +5,7 @@
5
import { BookListComponent } from './book-list/book-list.component';
6
import { BookDetailsComponent } from './book-details/book-details.component';
7
import { CreateBookComponent } from './create-book/create-book.component';
8
9
export const routes: Routes = [
10
{
@@ -32,6 +33,10 @@
32
{
33
path: 'admin/create',
34
component: CreateBookComponent
35
}
36
];
37
5
import { BookListComponent } from './book-list/book-list.component';
6
import { BookDetailsComponent } from './book-details/book-details.component';
7
import { CreateBookComponent } from './create-book/create-book.component';
8
+ import { EditBookComponent } from './edit-book/edit-book.component';
9
10
export const routes: Routes = [
11
{
33
{
34
path: 'admin/create',
35
component: CreateBookComponent
36
+ },
37
+ {
38
+ path: 'admin/edit/:isbn',
39
+ component: EditBookComponent
40
}
41
];
42
tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/app.module.ts RENAMED
@@ -1,7 +1,7 @@
1
import { CommonModule } from '@angular/common';
2
import { NgModule } from '@angular/core';
3
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
4
- import { FormsModule } from '@angular/forms';
5
import { DateValueAccessorModule } from 'angular-date-value-accessor';
6
7
import { AppRoutingModule } from './app-routing.module.one-app';
@@ -15,6 +15,7 @@
15
import { BookFormComponent } from './book-form/book-form.component';
16
import { CreateBookComponent } from './create-book/create-book.component';
17
import { FormMessagesComponent } from './form-messages/form-messages.component';
18
19
@NgModule({
20
declarations: [
@@ -26,13 +27,14 @@
26
SearchComponent,
27
BookFormComponent,
28
CreateBookComponent,
29
- FormMessagesComponent
30
],
31
imports: [
32
CommonModule,
33
HttpClientModule,
34
AppRoutingModule,
35
- FormsModule,
36
DateValueAccessorModule
37
],
38
providers: [
1
import { CommonModule } from '@angular/common';
2
import { NgModule } from '@angular/core';
3
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
4
+ import { ReactiveFormsModule } from '@angular/forms';
5
import { DateValueAccessorModule } from 'angular-date-value-accessor';
6
7
import { AppRoutingModule } from './app-routing.module.one-app';
15
import { BookFormComponent } from './book-form/book-form.component';
16
import { CreateBookComponent } from './create-book/create-book.component';
17
import { FormMessagesComponent } from './form-messages/form-messages.component';
18
+ import { EditBookComponent } from './edit-book/edit-book.component';
19
20
@NgModule({
21
declarations: [
27
SearchComponent,
28
BookFormComponent,
29
CreateBookComponent,
30
+ FormMessagesComponent,
31
+ EditBookComponent,
32
],
33
imports: [
34
CommonModule,
35
HttpClientModule,
36
AppRoutingModule,
37
+ ReactiveFormsModule,
38
DateValueAccessorModule
39
],
40
providers: [
tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/book-details/book-details.component.html RENAMED
@@ -33,6 +33,10 @@
33
(click)="removeBook()">
34
<i class="remove icon"></i> Buch löschen
35
</button>
36
</div>
37
38
<ng-template #loading>
33
(click)="removeBook()">
34
<i class="remove icon"></i> Buch löschen
35
</button>
36
+ <a class="ui tiny yellow labeled icon button"
37
+ [routerLink]="['../../admin/edit', book.isbn]">
38
+ <i class="write icon"></i> Buch bearbeiten
39
+ </a>
40
</div>
41
42
<ng-template #loading>
tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/book-form/book-form.component.html RENAMED
@@ -1,78 +1,70 @@
1
<form class="ui form"
2
- (ngSubmit)="submitForm()"
3
- #bookForm="ngForm">
4
5
<label>Buchtitel</label>
6
- <input
7
- name="title"
8
- [(ngModel)]="book.title"
9
- required
10
- #titleInput="ngModel">
11
<bm-form-messages
12
- [control]="titleInput"
13
controlName="title">
14
</bm-form-messages>
15
16
<label>Untertitel</label>
17
- <input
18
- name="subtitle"
19
- [(ngModel)]="book.subtitle">
20
21
<label>ISBN</label>
22
- <input
23
- name="isbn"
24
- [(ngModel)]="book.isbn"
25
- required
26
- minlength="10"
27
- maxlength="13"
28
- #isbnInput="ngModel">
29
<bm-form-messages
30
- [control]="isbnInput"
31
controlName="isbn">
32
</bm-form-messages>
33
34
<label>Erscheinungsdatum</label>
35
- <input
36
- type="date"
37
- name="published"
38
- [(ngModel)]="book.published"
39
useValueAsDate
40
- required
41
- #dateInput="ngModel">
42
<bm-form-messages
43
- [control]="dateInput"
44
controlName="published">
45
</bm-form-messages>
46
47
- <label>Autor</label>
48
- <input
49
- name="authors"
50
- [(ngModel)]="book.authors[0]"
51
- required
52
- #authorInput="ngModel">
53
<bm-form-messages
54
- [control]="authorInput"
55
controlName="authors">
56
</bm-form-messages>
57
58
<label>Beschreibung</label>
59
- <textarea
60
- name="description"
61
- [(ngModel)]="book.description"></textarea>
62
-
63
- <label>Bild</label>
64
- <div class="two fields">
65
- <div class="field">
66
- <input
67
- name="url"
68
- [(ngModel)]="book.thumbnails[0].url"
69
- placeholder="URL">
70
- </div>
71
- <div class="field">
72
- <input
73
- name="title"
74
- [(ngModel)]="book.thumbnails[0].title"
75
- placeholder="Titel">
76
</div>
77
</div>
78
1
<form class="ui form"
2
+ [formGroup]="bookForm"
3
+ (ngSubmit)="submitForm()">
4
5
<label>Buchtitel</label>
6
+ <input formControlName="title">
7
<bm-form-messages
8
+ [control]="bookForm.get('title')"
9
controlName="title">
10
</bm-form-messages>
11
12
<label>Untertitel</label>
13
+ <input formControlName="subtitle">
14
15
<label>ISBN</label>
16
+ <input formControlName="isbn">
17
<bm-form-messages
18
+ [control]="bookForm.get('isbn')"
19
controlName="isbn">
20
</bm-form-messages>
21
22
<label>Erscheinungsdatum</label>
23
+ <input type="date"
24
useValueAsDate
25
+ formControlName="published">
26
<bm-form-messages
27
+ [control]="bookForm.get('published')"
28
controlName="published">
29
</bm-form-messages>
30
31
+ <label>Autoren</label>
32
+ <button type="button" class="ui mini button"
33
+ (click)="addAuthorControl()">
34
+ + Autor
35
+ </button>
36
+ <div class="fields" formArrayName="authors">
37
+ <div class="sixteen wide field"
38
+ *ngFor="let c of authors.controls; index as i">
39
+ <input placeholder="Autor"
40
+ [formControlName]="i">
41
+ </div>
42
+ </div>
43
<bm-form-messages
44
+ [control]="bookForm.get('authors')"
45
controlName="authors">
46
</bm-form-messages>
47
48
<label>Beschreibung</label>
49
+ <textarea formControlName="description"></textarea>
50
+
51
+ <label>Bilder</label>
52
+ <button type="button" class="ui mini button"
53
+ (click)="addThumbnailControl()">
54
+ + Bild
55
+ </button>
56
+ <div formArrayName="thumbnails">
57
+ <div class="fields"
58
+ *ngFor="let c of thumbnails.controls; index as i"
59
+ [formGroupName]="i">
60
+ <div class="nine wide field">
61
+ <input placeholder="URL"
62
+ formControlName="url">
63
+ </div>
64
+ <div class="seven wide field">
65
+ <input placeholder="Titel"
66
+ formControlName="title">
67
+ </div>
68
</div>
69
</div>
70
tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/book-form/book-form.component.ts RENAMED
@@ -1,29 +1,111 @@
1
- import { Component, ViewChild, OnInit, Output, EventEmitter } from '@angular/core';
2
- import { NgForm } from '@angular/forms';
3
4
- import { Book } from '../shared/book';
5
- import { BookFactory } from '../shared/book-factory';
6
7
@Component({
8
selector: 'bm-book-form',
9
templateUrl: './book-form.component.html',
10
styleUrls: ['./book-form.component.css']
11
})
12
- export class BookFormComponent implements OnInit {
13
14
- book = BookFactory.empty();
15
16
@Output() submitBook = new EventEmitter<Book>();
17
- @ViewChild('bookForm', { static: true }) bookForm: NgForm;
18
19
-
20
- submitForm() {
21
- this.submitBook.emit(this.book);
22
23
- this.book = BookFactory.empty();
24
- this.bookForm.reset();
25
}
26
27
- ngOnInit() {
28
}
29
}
1
+ import { Component, OnInit, Input, Output, EventEmitter, OnChanges } from '@angular/core';
2
+ import { FormBuilder, FormGroup, FormArray, Validators } from '@angular/forms';
3
4
+ import { Book, Thumbnail } from '../shared/book';
5
6
@Component({
7
selector: 'bm-book-form',
8
templateUrl: './book-form.component.html',
9
styleUrls: ['./book-form.component.css']
10
})
11
+ export class BookFormComponent implements OnInit, OnChanges {
12
13
+ bookForm: FormGroup;
14
15
+ @Input() book: Book;
16
+ @Input() editing = false;
17
@Output() submitBook = new EventEmitter<Book>();
18
19
+ constructor(private fb: FormBuilder) { }
20
21
+ ngOnInit() {
22
+ this.initForm();
23
}
24
25
+ ngOnChanges() {
26
+ this.initForm();
27
+ this.setFormValues(this.book);
28
+ }
29
+
30
+ private setFormValues(book: Book) {
31
+ this.bookForm.patchValue(book);
32
+
33
+ this.bookForm.setControl(
34
+ 'authors',
35
+ this.buildAuthorsArray(book.authors)
36
+ );
37
+
38
+ this.bookForm.setControl(
39
+ 'thumbnails',
40
+ this.buildThumbnailsArray(book.thumbnails)
41
+ );
42
+ }
43
+
44
+ private initForm() {
45
+ if (this.bookForm) { return; }
46
+
47
+ this.bookForm = this.fb.group({
48
+ title: ['', Validators.required],
49
+ subtitle: [''],
50
+ isbn: [{ value: '', disabled: this.editing }, [
51
+ Validators.required,
52
+ Validators.minLength(10),
53
+ Validators.maxLength(13)
54
+ ]],
55
+ description: [''],
56
+ authors: this.buildAuthorsArray(['']),
57
+ thumbnails: this.buildThumbnailsArray([
58
+ { title: '', url: '' }
59
+ ]),
60
+ published: []
61
+ });
62
+ }
63
+
64
+ private buildAuthorsArray(values: string[]): FormArray {
65
+ return this.fb.array(values, Validators.required);
66
+ }
67
+
68
+ private buildThumbnailsArray(values: Thumbnail[]): FormArray {
69
+ return this.fb.array(
70
+ values.map(t => this.fb.group(t))
71
+ );
72
+ }
73
+
74
+ get authors(): FormArray {
75
+ return this.bookForm.get('authors') as FormArray;
76
+ }
77
+
78
+ get thumbnails(): FormArray {
79
+ return this.bookForm.get('thumbnails') as FormArray;
80
+ }
81
+
82
+ addAuthorControl() {
83
+ this.authors.push(this.fb.control(''));
84
+ }
85
+
86
+ addThumbnailControl() {
87
+ this.thumbnails.push(
88
+ this.fb.group({ url: '', title: '' })
89
+ );
90
+ }
91
+
92
+ submitForm() {
93
+ const formValue = this.bookForm.value;
94
+ const authors = formValue.authors
95
+ .filter(author => author);
96
+ const thumbnails = formValue.thumbnails
97
+ .filter(thumbnail => thumbnail.url);
98
+
99
+ const isbn = this.editing ? this.book.isbn : formValue.isbn;
100
+
101
+ const newBook: Book = {
102
+ ...formValue,
103
+ isbn,
104
+ authors,
105
+ thumbnails
106
+ };
107
+
108
+ this.submitBook.emit(newBook);
109
+ this.bookForm.reset();
110
}
111
}
tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/create-book/create-book.component.html RENAMED
@@ -1,3 +1,3 @@
1
<h1>Buch hinzufügen</h1>
2
- <bm-book-form (submitBook)="createBook($event)">
3
- </bm-book-form>
1
<h1>Buch hinzufügen</h1>
2
+
3
+ <bm-book-form (submitBook)="createBook($event)"></bm-book-form>
tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/create-book/create-book.component.ts RENAMED
@@ -1,5 +1,6 @@
1
import { Component, OnInit } from '@angular/core';
2
import { ActivatedRoute, Router } from '@angular/router';
3
4
import { Book } from '../shared/book';
5
import { BookStoreService } from '../shared/book-store.service';
1
import { Component, OnInit } from '@angular/core';
2
import { ActivatedRoute, Router } from '@angular/router';
3
+ import { map, switchMap } from 'rxjs/operators';
4
5
import { Book } from '../shared/book';
6
import { BookStoreService } from '../shared/book-store.service';
tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/edit-book/edit-book.component.html RENAMED
@@ -0,0 +1,8 @@
1
+ <h1>Buch bearbeiten</h1>
2
+
3
+ <bm-book-form
4
+ *ngIf="book"
5
+ (submitBook)="updateBook($event)"
6
+ [book]="book"
7
+ [editing]="true"
8
+ ></bm-book-form>
tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/edit-book/edit-book.component.ts RENAMED
@@ -0,0 +1,37 @@
1
+ import { Component, OnInit } from '@angular/core';
2
+ import { ActivatedRoute, Router } from '@angular/router';
3
+ import { map, switchMap } from 'rxjs/operators';
4
+
5
+ import { Book } from '../shared/book';
6
+ import { BookStoreService } from '../shared/book-store.service';
7
+
8
+ @Component({
9
+ selector: 'bm-edit-book',
10
+ templateUrl: './edit-book.component.html',
11
+ styleUrls: ['./edit-book.component.css']
12
+ })
13
+ export class EditBookComponent implements OnInit {
14
+
15
+ book: Book;
16
+
17
+ constructor(
18
+ private bs: BookStoreService,
19
+ private route: ActivatedRoute,
20
+ private router: Router
21
+ ) { }
22
+
23
+ ngOnInit() {
24
+ this.route.paramMap.pipe(
25
+ map(params => params.get('isbn')),
26
+ switchMap((isbn: string) => this.bs.getSingle(isbn))
27
+ )
28
+ .subscribe(book => this.book = book);
29
+ }
30
+
31
+ updateBook(book: Book) {
32
+ this.bs.update(book).subscribe(() => {
33
+ this.router.navigate(['../../..', 'books', book.isbn], { relativeTo: this.route });
34
+ });
35
+ }
36
+
37
+ }
tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/shared/book-factory.ts RENAMED
@@ -3,21 +3,6 @@
3
4
export class BookFactory {
5
6
- static empty(): Book {
7
- return {
8
- isbn: '',
9
- title: '',
10
- authors: [''],
11
- published: new Date(),
12
- subtitle: '',
13
- rating: 0,
14
- thumbnails: [
15
- { url: '', title: '' }
16
- ],
17
- description: ''
18
- };
19
- }
20
-
21
static fromRaw(b: BookRaw): Book {
22
return {
23
...b,
3
4
export class BookFactory {
5
6
static fromRaw(b: BookRaw): Book {
7
return {
8
...b,
tmp/src/app/book-monkey/iteration-4/{template-driven-forms → reactive-forms}/shared/book-store.service.ts RENAMED
@@ -46,6 +46,16 @@
46
);
47
}
48
49
remove(isbn: string): Observable<any> {
50
return this.http.delete(
51
`${this.api}/book/${isbn}`,
46
);
47
}
48
49
+ update(book: Book): Observable<any> {
50
+ return this.http.put(
51
+ `${this.api}/book/${book.isbn}`,
52
+ book,
53
+ { responseType: 'text' }
54
+ ).pipe(
55
+ catchError(this.errorHandler)
56
+ );
57
+ }
58
+
59
remove(isbn: string): Observable<any> {
60
return this.http.delete(
61
`${this.api}/book/${isbn}`,