@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { NgModule } from '@angular/core';
|
2 |
+
import { RouterModule, Routes } from '@angular/router';
|
3 |
+
import { BookCreateComponent } from './book-create/book-create.component';
|
4 |
+
|
5 |
+
const routes: Routes = [
|
6 |
+
{
|
7 |
+
path: 'admin',
|
8 |
+
redirectTo: 'admin/create'
|
9 |
+
},
|
10 |
+
{
|
11 |
+
path: 'admin/create',
|
12 |
+
component: BookCreateComponent,
|
13 |
+
}
|
14 |
+
];
|
15 |
+
|
16 |
+
@NgModule({
|
17 |
+
imports: [RouterModule.forChild(routes)],
|
18 |
+
exports: [RouterModule]
|
19 |
+
})
|
20 |
+
export class AdminRoutingModule { }
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { NgModule } from '@angular/core';
|
2 |
+
import { CommonModule } from '@angular/common';
|
3 |
+
import { FormsModule } from '@angular/forms';
|
4 |
+
|
5 |
+
import { AdminRoutingModule } from './admin-routing.module';
|
6 |
+
import { BookFormComponent } from './book-form/book-form.component';
|
7 |
+
import { BookCreateComponent } from './book-create/book-create.component';
|
8 |
+
|
9 |
+
@NgModule({
|
10 |
+
declarations: [
|
11 |
+
BookFormComponent,
|
12 |
+
BookCreateComponent
|
13 |
+
],
|
14 |
+
imports: [
|
15 |
+
CommonModule,
|
16 |
+
AdminRoutingModule,
|
17 |
+
FormsModule
|
18 |
+
],
|
19 |
+
})
|
20 |
+
export class AdminModule { }
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
1 |
+
<h1>Create Book</h1>
|
2 |
+
|
3 |
+
<bm-book-form (submitBook)="create($event)"></bm-book-form>
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
2 |
+
|
3 |
+
import { BookCreateComponent } from './book-create.component';
|
4 |
+
|
5 |
+
describe('BookCreateComponent', () => {
|
6 |
+
let component: BookCreateComponent;
|
7 |
+
let fixture: ComponentFixture<BookCreateComponent>;
|
8 |
+
|
9 |
+
beforeEach(async () => {
|
10 |
+
await TestBed.configureTestingModule({
|
11 |
+
declarations: [ BookCreateComponent ]
|
12 |
+
})
|
13 |
+
.compileComponents();
|
14 |
+
|
15 |
+
fixture = TestBed.createComponent(BookCreateComponent);
|
16 |
+
component = fixture.componentInstance;
|
17 |
+
fixture.detectChanges();
|
18 |
+
});
|
19 |
+
|
20 |
+
it('should create', () => {
|
21 |
+
expect(component).toBeTruthy();
|
22 |
+
});
|
23 |
+
});
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Component } from '@angular/core';
|
2 |
+
import { Router } from '@angular/router';
|
3 |
+
|
4 |
+
import { BookStoreService } from '../../shared/book-store.service';
|
5 |
+
import { Book } from '../../shared/book';
|
6 |
+
|
7 |
+
@Component({
|
8 |
+
selector: 'bm-book-create',
|
9 |
+
templateUrl: './book-create.component.html',
|
10 |
+
styleUrls: ['./book-create.component.css']
|
11 |
+
})
|
12 |
+
export class BookCreateComponent {
|
13 |
+
|
14 |
+
constructor(
|
15 |
+
private service: BookStoreService,
|
16 |
+
private router: Router
|
17 |
+
) { }
|
18 |
+
|
19 |
+
create(book: Book) {
|
20 |
+
this.service.create(book).subscribe(createdBook => {
|
21 |
+
this.router.navigate(['/books', createdBook.isbn]);
|
22 |
+
});
|
23 |
+
}
|
24 |
+
|
25 |
+
}
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<form (ngSubmit)="submitForm()" #form="ngForm">
|
2 |
+
<label for="title">Title</label>
|
3 |
+
<input
|
4 |
+
name="title"
|
5 |
+
id="title"
|
6 |
+
[(ngModel)]="book.title"
|
7 |
+
required>
|
8 |
+
|
9 |
+
<label for="isbn">ISBN</label>
|
10 |
+
<input
|
11 |
+
name="isbn"
|
12 |
+
id="isbn"
|
13 |
+
[(ngModel)]="book.isbn"
|
14 |
+
required
|
15 |
+
minlength="10"
|
16 |
+
maxlength="13">
|
17 |
+
|
18 |
+
<label for="author">Author</label>
|
19 |
+
<input
|
20 |
+
name="author"
|
21 |
+
id="author"
|
22 |
+
[(ngModel)]="book.authors[0]"
|
23 |
+
required>
|
24 |
+
|
25 |
+
<button type="submit" [disabled]="form.invalid">
|
26 |
+
Save
|
27 |
+
</button>
|
28 |
+
</form>
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
2 |
+
|
3 |
+
import { BookFormComponent } from './book-form.component';
|
4 |
+
|
5 |
+
describe('BookFormComponent', () => {
|
6 |
+
let component: BookFormComponent;
|
7 |
+
let fixture: ComponentFixture<BookFormComponent>;
|
8 |
+
|
9 |
+
beforeEach(async () => {
|
10 |
+
await TestBed.configureTestingModule({
|
11 |
+
declarations: [ BookFormComponent ]
|
12 |
+
})
|
13 |
+
.compileComponents();
|
14 |
+
|
15 |
+
fixture = TestBed.createComponent(BookFormComponent);
|
16 |
+
component = fixture.componentInstance;
|
17 |
+
fixture.detectChanges();
|
18 |
+
});
|
19 |
+
|
20 |
+
it('should create', () => {
|
21 |
+
expect(component).toBeTruthy();
|
22 |
+
});
|
23 |
+
});
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Component, Output, EventEmitter } from '@angular/core';
|
2 |
+
|
3 |
+
import { Book } from '../../shared/book';
|
4 |
+
|
5 |
+
@Component({
|
6 |
+
selector: 'bm-book-form',
|
7 |
+
templateUrl: './book-form.component.html',
|
8 |
+
styleUrls: ['./book-form.component.css']
|
9 |
+
})
|
10 |
+
export class BookFormComponent {
|
11 |
+
book: Book = {
|
12 |
+
isbn: '',
|
13 |
+
title: '',
|
14 |
+
authors: ['']
|
15 |
+
};
|
16 |
+
|
17 |
+
@Output() submitBook = new EventEmitter<Book>();
|
18 |
+
|
19 |
+
submitForm() {
|
20 |
+
this.submitBook.emit(this.book);
|
21 |
+
}
|
22 |
+
}
|
@@ -1,6 +1,7 @@
|
|
1 |
<nav>
|
2 |
<a routerLink="/home" routerLinkActive="active" ariaCurrentWhenActive="page">Home</a>
|
3 |
<a routerLink="/books" routerLinkActive="active" ariaCurrentWhenActive="page">Books</a>
|
|
|
4 |
<div class="actions">
|
5 |
<button class="green"
|
6 |
(click)="auth.login()"
|
1 |
<nav>
|
2 |
<a routerLink="/home" routerLinkActive="active" ariaCurrentWhenActive="page">Home</a>
|
3 |
<a routerLink="/books" routerLinkActive="active" ariaCurrentWhenActive="page">Books</a>
|
4 |
+
<a routerLink="/admin" routerLinkActive="active" ariaCurrentWhenActive="page">Administration</a>
|
5 |
<div class="actions">
|
6 |
<button class="green"
|
7 |
(click)="auth.login()"
|
@@ -8,6 +8,7 @@ import { BooksModule } from './books/books.module';
|
|
8 |
import { HomeComponent } from './home/home.component';
|
9 |
import { SearchComponent } from './search/search.component';
|
10 |
import { AuthInterceptor } from './shared/auth.interceptor';
|
|
|
11 |
|
12 |
@NgModule({
|
13 |
declarations: [
|
@@ -19,7 +20,8 @@ import { AuthInterceptor } from './shared/auth.interceptor';
|
|
19 |
BrowserModule,
|
20 |
AppRoutingModule,
|
21 |
HttpClientModule,
|
22 |
-
BooksModule
|
|
|
23 |
],
|
24 |
providers: [
|
25 |
{
|
8 |
import { HomeComponent } from './home/home.component';
|
9 |
import { SearchComponent } from './search/search.component';
|
10 |
import { AuthInterceptor } from './shared/auth.interceptor';
|
11 |
+
import { AdminModule } from './admin/admin.module';
|
12 |
|
13 |
@NgModule({
|
14 |
declarations: [
|
20 |
BrowserModule,
|
21 |
AppRoutingModule,
|
22 |
HttpClientModule,
|
23 |
+
BooksModule,
|
24 |
+
AdminModule
|
25 |
],
|
26 |
providers: [
|
27 |
{
|
@@ -37,4 +37,8 @@ export class BookStoreService {
|
|
37 |
})
|
38 |
);
|
39 |
}
|
|
|
|
|
|
|
|
|
40 |
}
|
37 |
})
|
38 |
);
|
39 |
}
|
40 |
+
|
41 |
+
create(book: Book): Observable<Book> {
|
42 |
+
return this.http.post<Book>(`${this.apiUrl}/books`, book);
|
43 |
+
}
|
44 |
}
|