Browse Source

refactor(bookstore-angular): sync via docs

pull/1633/head
mehmet-erim 7 years ago
parent
commit
373f94cb61
  1. 2
      samples/BookStore-Angular-MongoDb/angular/src/app/app-routing.module.ts
  2. 102
      samples/BookStore-Angular-MongoDb/angular/src/app/books/book-list/book-list.component.html
  3. 0
      samples/BookStore-Angular-MongoDb/angular/src/app/books/book-list/book-list.component.scss
  4. 25
      samples/BookStore-Angular-MongoDb/angular/src/app/books/book-list/book-list.component.spec.ts
  5. 91
      samples/BookStore-Angular-MongoDb/angular/src/app/books/book-list/book-list.component.ts
  6. 10
      samples/BookStore-Angular-MongoDb/angular/src/app/books/books-routing.module.ts
  7. 109
      samples/BookStore-Angular-MongoDb/angular/src/app/books/books.component.html
  8. 69
      samples/BookStore-Angular-MongoDb/angular/src/app/books/books.component.ts
  9. 3
      samples/BookStore-Angular-MongoDb/angular/src/app/books/books.module.ts
  10. 0
      samples/BookStore-Angular-MongoDb/angular/src/app/books/shared/books.service.spec.ts
  11. 31
      samples/BookStore-Angular-MongoDb/angular/src/app/books/shared/books.service.ts
  12. 4
      samples/BookStore-Angular-MongoDb/angular/src/app/home/home-routing.module.ts
  13. 13
      samples/BookStore-Angular-MongoDb/angular/src/app/store/actions/books.actions.ts
  14. 19
      samples/BookStore-Angular-MongoDb/angular/src/app/store/models/books.ts
  15. 39
      samples/BookStore-Angular-MongoDb/angular/src/app/store/states/books.state.ts
  16. 4
      samples/BookStore-Angular-MongoDb/angular/src/environments/environment.hmr.ts
  17. 4
      samples/BookStore-Angular-MongoDb/angular/src/environments/environment.prod.ts
  18. 4
      samples/BookStore-Angular-MongoDb/angular/src/environments/environment.ts

2
samples/BookStore-Angular-MongoDb/angular/src/app/app-routing.module.ts

@ -4,6 +4,7 @@ import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ABP } from '@abp/ng.core';
import { TENANT_MANAGEMENT_ROUTES } from '@abp/ng.tenant-management';
import { ApplicationLayoutComponent } from '@abp/ng.theme.basic';
const routes: Routes = [
{
@ -33,6 +34,7 @@ const routes: Routes = [
},
{
path: 'books',
component: ApplicationLayoutComponent,
loadChildren: () => import('./books/books.module').then(m => m.BooksModule),
data: {
routes: {

102
samples/BookStore-Angular-MongoDb/angular/src/app/books/book-list/book-list.component.html

@ -0,0 +1,102 @@
<div id="wrapper" class="card">
<div class="card-header">
<div class="row">
<div class="col col-md-6">
<h5 class="card-title">
Books
</h5>
</div>
<div class="text-right col col-md-6">
<button id="create-role" class="btn btn-primary" type="button" (click)="onAdd()">
<i class="fa fa-plus mr-1"></i> <span>New book</span>
</button>
</div>
</div>
</div>
<div class="card-body">
<p-table [value]="books$ | async" [loading]="loading" [paginator]="true" [rows]="10">
<ng-template pTemplate="header">
<tr>
<th>Actions</th>
<th>Book name</th>
<th>Book type</th>
<th>Publish date</th>
<th>Price</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-data>
<tr>
<td>
<div ngbDropdown class="d-inline-block">
<button
class="btn btn-primary btn-sm dropdown-toggle"
data-toggle="dropdown"
aria-haspopup="true"
ngbDropdownToggle
>
<i class="fa fa-cog mr-1"></i>Actions
</button>
<div ngbDropdownMenu>
<button ngbDropdownItem (click)="onEdit(data.id)">Edit</button>
<button ngbDropdownItem (click)="delete(data.id, data.name)">
Delete
</button>
</div>
</div>
</td>
<td>{{ data.name }}</td>
<td>{{ booksType[data.type] }}</td>
<td>{{ data.publishDate | date }}</td>
<td>{{ data.price }}</td>
</tr>
</ng-template>
</p-table>
</div>
</div>
<abp-modal [(visible)]="isModalOpen">
<ng-template #abpHeader>
<h3>{{ selectedBook.id ? 'Edit' : 'New Book' }}</h3>
</ng-template>
<ng-template #abpBody>
<form [formGroup]="form">
<div class="form-group">
<label for="book-name">Name</label><span> * </span>
<input type="text" id="book-name" class="form-control" formControlName="name" autofocus />
</div>
<div class="form-group">
<label for="book-price">Price</label><span> * </span>
<input type="number" id="book-price" class="form-control" formControlName="price" />
</div>
<div class="form-group">
<label for="book-type">Type</label><span> * </span>
<select class="form-control" id="book-type" formControlName="type">
<option [ngValue]="null">Select a book type</option>
<option [ngValue]="booksType[type]" *ngFor="let type of bookTypeArr"> {{ type }}</option>
</select>
</div>
<div class="form-group">
<label>Publish date</label><span> * </span>
<input
#datepicker="ngbDatepicker"
class="form-control"
name="datepicker"
formControlName="publishDate"
ngbDatepicker
(click)="datepicker.toggle()"
/>
</div>
</form>
</ng-template>
<ng-template #abpFooter>
<button type="button" class="btn btn-secondary" #abpClose>
Cancel
</button>
<abp-button iconClass="fa fa-check" (click)="save()">Save</abp-button>
</ng-template>
</abp-modal>

0
samples/BookStore-Angular-MongoDb/angular/src/app/books/book-list/book-list.component.scss

25
samples/BookStore-Angular-MongoDb/angular/src/app/books/book-list/book-list.component.spec.ts

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BookListComponent } from './book-list.component';
describe('BookListComponent', () => {
let component: BookListComponent;
let fixture: ComponentFixture<BookListComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BookListComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BookListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

91
samples/BookStore-Angular-MongoDb/angular/src/app/books/book-list/book-list.component.ts

@ -0,0 +1,91 @@
import { Component, OnInit } from '@angular/core';
import { Store, Select } from '@ngxs/store';
import { BooksState } from '../../store/states';
import { Observable } from 'rxjs';
import { Books } from '../../store/models';
import { GetBooks, CreateUpdateBook, DeleteBook } from '../../store/actions';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';
import { BooksService } from '../shared/books.service';
import { ConfirmationService, Toaster } from '@abp/ng.theme.shared';
@Component({
selector: 'app-book-list',
templateUrl: './book-list.component.html',
styleUrls: ['./book-list.component.scss'],
providers: [{ provide: NgbDateAdapter, useClass: NgbDateNativeAdapter }],
})
export class BookListComponent implements OnInit {
@Select(BooksState.getBooks)
books$: Observable<Books.Book[]>;
booksType = Books.BookType;
loading = false;
isModalOpen = false;
form: FormGroup;
bookTypeArr = Object.keys(Books.BookType).filter(bookType => typeof this.booksType[bookType] === 'number');
selectedBook = {} as Books.Book;
constructor(
private store: Store,
private fb: FormBuilder,
private booksService: BooksService,
private confirmationService: ConfirmationService,
) {}
ngOnInit() {
this.loading = true;
this.store.dispatch(new GetBooks()).subscribe(() => {
this.loading = false;
});
}
buildForm() {
this.form = this.fb.group({
name: [this.selectedBook.name || '', Validators.required],
type: this.selectedBook.type || null,
publishDate: this.selectedBook.publishDate ? new Date(this.selectedBook.publishDate) : null,
price: this.selectedBook.price || null,
});
}
onAdd() {
this.selectedBook = {} as Books.Book;
this.buildForm();
this.isModalOpen = true;
}
onEdit(id: string) {
this.booksService.getById(id).subscribe(book => {
this.selectedBook = book;
this.buildForm();
this.isModalOpen = true;
});
}
save() {
if (this.form.invalid) {
return;
}
this.store.dispatch(new CreateUpdateBook(this.form.value, this.selectedBook.id)).subscribe(() => {
this.isModalOpen = false;
this.form.reset();
});
}
delete(id: string, name: string) {
this.confirmationService
.error(`${name} will be deleted. Do you confirm that?`, 'Are you sure?')
.subscribe(status => {
if (status === Toaster.Status.confirm) {
this.store.dispatch(new DeleteBook(id));
}
});
}
}

10
samples/BookStore-Angular-MongoDb/angular/src/app/books/books-routing.module.ts

@ -1,10 +1,14 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LayoutApplicationComponent } from '@abp/ng.theme.basic';
import { RouterModule, Routes } from '@angular/router';
import { BooksComponent } from './books.component';
import { BookListComponent } from './book-list/book-list.component';
const routes: Routes = [
{ path: '', component: LayoutApplicationComponent, children: [{ path: '', component: BooksComponent }] },
{
path: '',
component: BooksComponent,
children: [{ path: '', component: BookListComponent }],
},
];
@NgModule({

109
samples/BookStore-Angular-MongoDb/angular/src/app/books/books.component.html

@ -1,108 +1 @@
<div id="wrapper" class="card">
<div class="card-header">
<div class="row">
<div class="col col-md-6">
<h5 class="card-title">
Books
</h5>
</div>
<div class="text-right col col-md-6">
<button id="create-role" class="btn btn-primary" type="button" (click)="onAdd()">
<i class="fa fa-plus mr-1"></i> <span>New book</span>
</button>
</div>
</div>
</div>
<div class="card-body">
<p-table [value]="books$ | async" [loading]="loading" [paginator]="true" [rows]="10">
<ng-template pTemplate="header">
<tr>
<th>Actions</th>
<th>Book name</th>
<th>Book type</th>
<th>Publish date</th>
<th>Price</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-data>
<tr>
<td>
<div ngbDropdown class="d-inline-block">
<button
class="btn btn-primary btn-sm dropdown-toggle"
data-toggle="dropdown"
aria-haspopup="true"
ngbDropdownToggle
>
<i class="fa fa-cog mr-1"></i>Actions
</button>
<div ngbDropdownMenu>
<button ngbDropdownItem (click)="onEdit(data.id)">Edit</button>
<!-- <button ngbDropdownItem (click)="delete(data.id, data.name)">
Delete
</button> -->
</div>
</div>
</td>
<td>{{ data.name }}</td>
<td>{{ bookType[data.type] }}</td>
<td>{{ data.publishDate | date }}</td>
<td>{{ data.price }}</td>
</tr>
</ng-template>
</p-table>
</div>
</div>
<abp-modal [(visible)]="isModalOpen">
<ng-template #abpHeader>
<h3>{{ selectedBook?.id ? 'Edit' : 'New Book' }}</h3>
</ng-template>
<ng-template #abpBody>
<form [formGroup]="form">
<div class="form-group">
<label for="book-name">Name</label><span> * </span>
<input type="text" id="book-name" class="form-control" formControlName="name" autofocus />
</div>
<div class="form-group">
<label for="book-price">Price</label>
<input type="number" id="book-price" class="form-control" formControlName="price" />
</div>
<div class="form-group">
<label for="book-type">Type</label>
<select class="form-control" id="book-type" formControlName="type">
<option [ngValue]="null">Select a book type</option>
<option [ngValue]="bookType[type]" *ngFor="let type of bookTypes"> {{ type }}</option>
</select>
</div>
<div class="form-group">
<label>Publish date</label>
<input
#datepicker="ngbDatepicker"
class="form-control"
name="datepicker"
formControlName="publishDate"
ngbDatepicker
(click)="datepicker.toggle()"
/>
</div>
</form>
</ng-template>
<ng-template #abpFooter>
<button type="button" class="btn btn-secondary" #abpClose>
Cancel
</button>
<abp-button
[requestType]="['POST', 'PUT']"
requestURLContainSearchValue="book"
iconClass="fa fa-check"
(click)="save()"
>Save</abp-button
>
</ng-template>
</abp-modal>
<router-outlet></router-outlet>

69
samples/BookStore-Angular-MongoDb/angular/src/app/books/books.component.ts

@ -1,73 +1,8 @@
import { Component, OnInit } from '@angular/core';
import { Store, Select } from '@ngxs/store';
import { BooksState } from '../store/states';
import { Observable } from 'rxjs';
import { Books } from '../store/models';
import { BooksGet, BooksSave } from '../store/actions';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { NgbDateAdapter, NgbDateNativeAdapter } from '@ng-bootstrap/ng-bootstrap';
import { BooksService } from './services/books.service';
import { Component } from '@angular/core';
@Component({
selector: 'app-books',
templateUrl: './books.component.html',
styleUrls: ['./books.component.scss'],
providers: [{ provide: NgbDateAdapter, useClass: NgbDateNativeAdapter }],
})
export class BooksComponent implements OnInit {
@Select(BooksState.getBooks)
books$: Observable<Books.Item[]>;
bookType = Books.Type;
bookTypes = Object.keys(Books.Type).filter(bookType => typeof this.bookType[bookType] === 'number');
loading = false;
isModalOpen = false;
form: FormGroup;
selectedBook = {} as Books.Item;
constructor(private store: Store, private fb: FormBuilder, private booksService: BooksService) {}
ngOnInit() {
this.loading = true;
this.store.dispatch(new BooksGet()).subscribe(() => (this.loading = false));
}
buildForm() {
this.form = this.fb.group({
name: [this.selectedBook.name || '', Validators.required],
type: this.selectedBook.type || null,
publishDate: this.selectedBook.publishDate ? new Date(this.selectedBook.publishDate) : null,
price: this.selectedBook.price || null,
});
}
onAdd() {
this.selectedBook = {} as Books.Item;
this.buildForm();
this.isModalOpen = true;
}
onEdit(id: string) {
this.booksService.getById(id).subscribe(book => {
this.selectedBook = book;
this.buildForm();
this.isModalOpen = true;
});
}
save() {
if (this.form.invalid) {
return;
}
this.store.dispatch(new BooksSave(this.form.value, this.selectedBook.id)).subscribe(() => {
this.isModalOpen = false;
this.form.reset();
});
}
}
export class BooksComponent {}

3
samples/BookStore-Angular-MongoDb/angular/src/app/books/books.module.ts

@ -5,9 +5,10 @@ import { BooksRoutingModule } from './books-routing.module';
import { BooksComponent } from './books.component';
import { SharedModule } from '../shared/shared.module';
import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap';
import { BookListComponent } from './book-list/book-list.component';
@NgModule({
declarations: [BooksComponent],
declarations: [BooksComponent, BookListComponent],
imports: [CommonModule, BooksRoutingModule, SharedModule, NgbDatepickerModule],
})
export class BooksModule {}

0
samples/BookStore-Angular-MongoDb/angular/src/app/books/services/books.service.spec.ts → samples/BookStore-Angular-MongoDb/angular/src/app/books/shared/books.service.spec.ts

31
samples/BookStore-Angular-MongoDb/angular/src/app/books/services/books.service.ts → samples/BookStore-Angular-MongoDb/angular/src/app/books/shared/books.service.ts

@ -18,32 +18,41 @@ export class BooksService {
return this.rest.request<null, Books.Response>(request);
}
getById(id: string): Observable<Books.Item> {
create(body: Books.CreateUpdateBookInput): Observable<Books.Book> {
const request: Rest.Request<Books.CreateUpdateBookInput> = {
method: 'POST',
url: '/api/app/book',
body,
};
return this.rest.request<Books.CreateUpdateBookInput, Books.Book>(request);
}
getById(id: string): Observable<Books.Book> {
const request: Rest.Request<null> = {
method: 'GET',
url: `/api/app/book/${id}`,
};
return this.rest.request<null, Books.Item>(request);
return this.rest.request<null, Books.Book>(request);
}
update(body: Books.SaveRequest, id: string): Observable<Books.Item> {
const request: Rest.Request<Books.SaveRequest> = {
update(body: Books.CreateUpdateBookInput, id: string): Observable<Books.Book> {
const request: Rest.Request<Books.CreateUpdateBookInput> = {
method: 'PUT',
url: `/api/app/book/${id}`,
body,
};
return this.rest.request<Books.SaveRequest, Books.Item>(request);
return this.rest.request<Books.CreateUpdateBookInput, Books.Book>(request);
}
add(body: Books.SaveRequest): Observable<Books.Item> {
const request: Rest.Request<Books.SaveRequest> = {
method: 'POST',
url: '/api/app/book',
body,
delete(id: string): Observable<null> {
const request: Rest.Request<null> = {
method: 'DELETE',
url: `/api/app/book/${id}`,
};
return this.rest.request<Books.SaveRequest, Books.Item>(request);
return this.rest.request<null, null>(request);
}
}

4
samples/BookStore-Angular-MongoDb/angular/src/app/home/home-routing.module.ts

@ -1,12 +1,12 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home.component';
import { LayoutApplicationComponent } from '@abp/ng.theme.basic';
import { ApplicationLayoutComponent } from '@abp/ng.theme.basic';
const routes: Routes = [
{
path: '',
component: LayoutApplicationComponent,
component: ApplicationLayoutComponent,
children: [{ path: '', component: HomeComponent }],
},
];

13
samples/BookStore-Angular-MongoDb/angular/src/app/store/actions/books.actions.ts

@ -1,10 +1,15 @@
import { Books } from '../models';
export class BooksGet {
export class GetBooks {
static readonly type = '[Books] Get';
}
export class BooksSave {
static readonly type = '[Books] Save';
constructor(public payload: Books.SaveRequest, public id?: string) {}
export class CreateUpdateBook {
static readonly type = '[Books] Create Update Book';
constructor(public payload: Books.CreateUpdateBookInput, public id?: string) {}
}
export class DeleteBook {
static readonly type = '[Books] Delete';
constructor(public id: string) {}
}

19
samples/BookStore-Angular-MongoDb/angular/src/app/store/models/books.ts

@ -1,15 +1,16 @@
import { ABP } from '@abp/ng.core';
export namespace Books {
export interface State {
data: Response;
books: Response;
}
export type Response = ABP.PagedResponse<Item>;
export interface Response {
items: Book[];
totalCount: number;
}
export interface Item {
export interface Book {
name: string;
type: Type;
type: BookType;
publishDate: string;
price: number;
lastModificationTime: string;
@ -19,7 +20,7 @@ export namespace Books {
id: string;
}
export enum Type {
export enum BookType {
Undefined,
Adventure,
Biography,
@ -31,9 +32,9 @@ export namespace Books {
Poetry,
}
export interface SaveRequest {
export interface CreateUpdateBookInput {
name: string;
type: Type;
type: BookType;
publishDate: string;
price: number;
}

39
samples/BookStore-Angular-MongoDb/angular/src/app/store/states/books.state.ts

@ -1,36 +1,47 @@
import { State, Action, StateContext, Selector } from '@ngxs/store';
import { BooksGet, BooksSave } from '../actions/books.actions';
import { Books } from '../models/books';
import { BooksService } from '../../books/services/books.service';
import { BooksService } from '../../books/shared/books.service';
import { tap, switchMap } from 'rxjs/operators';
import { GetBooks, CreateUpdateBook, DeleteBook } from '../actions/books.actions';
@State<Books.State>({
name: 'BooksState',
defaults: { data: {} } as Books.State,
defaults: { books: {} } as Books.State,
})
export class BooksState {
@Selector()
static getBooks({ data }: Books.State) {
return data.items || [];
static getBooks({ books }: Books.State) {
return books.items || [];
}
constructor(private booksService: BooksService) {}
@Action(BooksGet)
getBooks({ patchState }: StateContext<Books.State>) {
@Action(GetBooks)
get({ patchState }: StateContext<Books.State>) {
return this.booksService.get().pipe(
tap(data => {
tap(books => {
patchState({
data,
books,
});
}),
);
}
@Action(BooksSave)
addBooks({ dispatch }: StateContext<Books.State>, { payload, id }: BooksSave) {
return (id ? this.booksService.update(payload, id) : this.booksService.add(payload)).pipe(
switchMap(() => dispatch(new BooksGet())),
);
@Action(CreateUpdateBook)
save({ dispatch }: StateContext<Books.State>, { payload, id }: CreateUpdateBook) {
let request;
if (id) {
request = this.booksService.update(payload, id);
} else {
request = this.booksService.create(payload);
}
return request.pipe(switchMap(() => dispatch(new GetBooks())));
}
@Action(DeleteBook)
delete({ dispatch }: StateContext<Books.State>, { id }: DeleteBook) {
return this.booksService.delete(id).pipe(switchMap(() => dispatch(new GetBooks())));
}
}

4
samples/BookStore-Angular-MongoDb/angular/src/environments/environment.hmr.ts

@ -1,6 +1,10 @@
export const environment = {
production: false,
hmr: true,
application: {
name: 'BookStore',
logoUrl: '',
},
oAuthConfig: {
issuer: 'https://localhost:44359',
clientId: 'BookStore_ConsoleTestApp',

4
samples/BookStore-Angular-MongoDb/angular/src/environments/environment.prod.ts

@ -1,6 +1,10 @@
export const environment = {
production: true,
hmr: false,
application: {
name: 'BookStore',
logoUrl: '',
},
oAuthConfig: {
issuer: 'https://localhost:44359',
clientId: 'BookStore_ConsoleTestApp',

4
samples/BookStore-Angular-MongoDb/angular/src/environments/environment.ts

@ -1,6 +1,10 @@
export const environment = {
production: false,
hmr: false,
application: {
name: 'BookStore',
logoUrl: '',
},
oAuthConfig: {
issuer: 'https://localhost:44359',
clientId: 'BookStore_ConsoleTestApp',

Loading…
Cancel
Save