From 141a9a22466093f4c0288bc2c62aada710819c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Ca=C3=B1izares=20Est=C3=A9vez?= Date: Fri, 18 Nov 2016 15:55:40 +0100 Subject: [PATCH] catalog integration with real service in Spa web application (pagination, brand & type filter, etc.). --- .../Client/modules/app.module.ts | 1 - .../modules/catalog/catalog.component.html | 35 +++----- .../modules/catalog/catalog.component.ts | 86 ++++++++++++++++--- .../Client/modules/catalog/catalog.module.ts | 6 +- .../Client/modules/catalog/catalog.service.ts | 37 +++++++- .../shared/components/pager/pager.html | 29 +++++++ .../shared/components/pager/pager.scss | 0 .../modules/shared/components/pager/pager.ts | 33 +++++++ .../modules/shared/layout/header.component.ts | 4 +- .../modules/shared/models/catalog.model.ts | 10 ++- .../shared/models/catalogBrand.model.ts | 4 + .../shared/models/catalogItem.model.ts | 12 ++- .../shared/models/catalogType.model.ts | 4 + .../shared/models/operation-result.model.ts | 3 - .../modules/shared/models/pager.model.ts | 6 ++ .../modules/shared/models/user.model.ts | 4 - .../modules/shared/services/auth.service.ts | 37 -------- .../modules/shared/services/data.service.ts | 14 +-- .../Client/modules/shared/shared.module.ts | 11 ++- 19 files changed, 230 insertions(+), 106 deletions(-) create mode 100644 src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/components/pager/pager.html create mode 100644 src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/components/pager/pager.scss create mode 100644 src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/components/pager/pager.ts create mode 100644 src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalogBrand.model.ts create mode 100644 src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalogType.model.ts delete mode 100644 src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/operation-result.model.ts create mode 100644 src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/pager.model.ts delete mode 100644 src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/user.model.ts delete mode 100644 src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/auth.service.ts diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/app.module.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/app.module.ts index 2716bb5a7..458999ebf 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/app.module.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/app.module.ts @@ -15,7 +15,6 @@ import { CatalogModule } from './catalog/catalog.module'; imports: [ BrowserModule, routing, - // FormsModule, HttpModule, // Only module that app module loads SharedModule.forRoot(), diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.component.html b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.component.html index ccfbe5e48..81fa2fb73 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.component.html +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.component.html @@ -7,36 +7,21 @@
- + - +
+
+
-
- +
+
-
- - -
-
- - -
-
- - -
-
- - -
-
\ No newline at end of file +
+ \ No newline at end of file diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.component.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.component.ts index a3772900c..e4ec52ef0 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.component.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.component.ts @@ -1,28 +1,86 @@ -import { Component, OnInit } from '@angular/core'; -import { CatalogService } from './catalog.service'; -import { Catalog } from '../shared/models/catalog.model'; -import { CatalogItem } from '../shared/models/catalogItem.model'; +import { Component, OnInit } from '@angular/core'; +import { CatalogService } from './catalog.service'; +import { ICatalog } from '../shared/models/catalog.model'; +import { ICatalogItem } from '../shared/models/catalogItem.model'; +import { ICatalogType } from '../shared/models/catalogType.model'; +import { ICatalogBrand } from '../shared/models/catalogBrand.model'; +import { IPager } from '../shared/models/pager.model'; @Component({ - selector: 'appc-catalog', + selector: 'esh-catalog', styleUrls: ['./catalog.component.scss'], templateUrl: './catalog.component.html' }) export class CatalogComponent implements OnInit { - private brands: any[]; - private types: any[]; - private items: CatalogItem[]; - private filteredItems: any[]; - private catalog: Catalog; + brands: ICatalogBrand[]; + types: ICatalogType[]; + catalog: ICatalog; + brandSelected: number; + typeSelected: number; + paginationInfo: IPager; constructor(private service: CatalogService) { } ngOnInit() { - console.log('catalog component loaded'); - this.service.getCatalog().subscribe((catalog: Catalog) => { + this.getBrands(); + this.getCatalog(10,0); + this.getTypes(); + } + + onFilterApplied(event: any) { + event.preventDefault(); + this.getCatalog(this.paginationInfo.itemsPage, this.paginationInfo.actualPage, this.brandSelected, this.typeSelected); + } + + onBrandFilterChanged(event: any, value: number) { + event.preventDefault(); + this.brandSelected = value; + } + + onTypeFilterChanged(event: any, value: number) { + event.preventDefault(); + this.typeSelected = value; + } + + onPageChanged(value: any) { + console.log('catalog pager event fired' + value); + event.preventDefault(); + this.paginationInfo.actualPage = value; + this.getCatalog(this.paginationInfo.itemsPage, value); + } + + getCatalog(pageSize:number, pageIndex: number, brand?: number, type?: number) { + this.service.getCatalog(brand, type).subscribe(catalog => { this.catalog = catalog; - this.items = catalog.data; - console.log(this.items.length + ' catalog items retrieved from api'); + console.log('catalog items retrieved: ' + catalog.count); + + this.paginationInfo = { + actualPage : catalog.pageIndex, + itemsPage : catalog.pageSize, + totalItems : catalog.count, + totalPages : (catalog.count / catalog.pageSize) + }; + + console.log(this.paginationInfo); + }); + } + + getTypes() { + this.service.getTypes().subscribe(types => { + this.types = types; + let alltypes = { id: null, type: 'All' }; + this.types.unshift(alltypes); + console.log('types retrieved: ' + types.length); + }); + } + + getBrands() { + this.service.getBrands().subscribe(brands => { + this.brands = brands; + let allBrands = { id: null, brand: 'All' }; + this.brands.unshift(allBrands); + console.log('brands retrieved: ' + brands.length); }); } } + diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.module.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.module.ts index 4ecc504b7..64e961d03 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.module.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.module.ts @@ -1,12 +1,16 @@ import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { SharedModule } from '../shared/shared.module'; import { CatalogComponent } from './catalog.component'; import { routing } from './catalog.routes'; import { CatalogService } from './catalog.service'; +import { Pager } from '../shared/components/pager/pager'; + @NgModule({ - imports: [routing], + imports: [routing, BrowserModule, SharedModule], declarations: [CatalogComponent], providers: [CatalogService] }) diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.service.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.service.ts index 8932531da..a5e92133a 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.service.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/catalog/catalog.service.ts @@ -1,15 +1,48 @@ import { Injectable } from '@angular/core'; +import { Response } from '@angular/http'; import { DataService } from '../shared/services/data.service'; +import { ICatalog } from '../shared/models/catalog.model'; +import { ICatalogBrand } from '../shared/models/catalogBrand.model'; +import { ICatalogType } from '../shared/models/catalogType.model'; + +import 'rxjs/Rx'; +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/observable/throw'; +import { Observer } from 'rxjs/Observer'; +import 'rxjs/add/operator/map'; @Injectable() export class CatalogService { private catalogUrl: string = 'http://eshopcontainers:5101/api/v1/catalog/items'; + private brandUrl: string = 'http://eshopcontainers:5101/api/v1/catalog/catalogbrands'; + private typesUrl: string = 'http://eshopcontainers:5101/api/v1/catalog/catalogtypes'; constructor(private service: DataService) { } - getCatalog(){ - return this.service.get(this.catalogUrl); + getCatalog(pageIndex: number, pageSize: number, brand: number, type: number): Observable { + var url = this.catalogUrl; + if (brand || type) { + url = this.catalogUrl + '/type/' + ((type) ? type.toString() : 'null') + '/brand/' + ((brand) ? brand.toString() : 'null'); + } + + url = url + '?pageIndex=' + pageIndex + '&pageSize=' + pageSize; + + return this.service.get(url).map((response: Response) => { + return response.json(); + }); + } + + getBrands(): Observable { + return this.service.get(this.brandUrl).map((response: Response) => { + return response.json(); + }); } + + getTypes(): Observable { + return this.service.get(this.typesUrl).map((response: Response) => { + return response.json(); + }); + }; } \ No newline at end of file diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/components/pager/pager.html b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/components/pager/pager.html new file mode 100644 index 000000000..3aa344d6f --- /dev/null +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/components/pager/pager.html @@ -0,0 +1,29 @@ +
+
+ +
+
Showing {{model?.itemsPage}} of {{model?.totalItems}} products - Page {{model?.actualPage}} - {{model?.totalPages}}
+
+ +
+
\ No newline at end of file diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/components/pager/pager.scss b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/components/pager/pager.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/components/pager/pager.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/components/pager/pager.ts new file mode 100644 index 000000000..41910a0ca --- /dev/null +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/components/pager/pager.ts @@ -0,0 +1,33 @@ +import { Component, OnInit, Output, Input, EventEmitter } from '@angular/core'; + +import { IPager } from '../../models/pager.model'; + +@Component({ + selector: 'esh-pager', + templateUrl: './pager.html', + styleUrls: ['./pager.scss'] +}) +export class Pager implements OnInit { + + @Output() + changed: EventEmitter = new EventEmitter(); + + @Input() + model: IPager; + + ngOnInit() { + console.log(this.model); + } + + onNextClicked(event: any) { + event.preventDefault(); + console.log('Pager Next Clicked'); + this.changed.emit(this.model.actualPage + 1); + } + + onPreviousCliked(event: any) { + event.preventDefault(); + this.changed.emit(this.model.actualPage - 1); + } + +} diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/layout/header.component.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/layout/header.component.ts index 6e23eb2c0..fb69eb730 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/layout/header.component.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/layout/header.component.ts @@ -1,8 +1,6 @@ import { Component, Inject } from '@angular/core'; import { Router } from '@angular/router'; -import { AuthService } from '../services/auth.service'; - @Component({ selector: 'appc-header', styleUrls: ['./header.component.scss'], @@ -10,7 +8,7 @@ import { AuthService } from '../services/auth.service'; }) export class HeaderComponent { isCollapsed: boolean = true; - constructor(private router: Router, private authService: AuthService) { } + constructor(private router: Router) { } toggleNav() { this.isCollapsed = !this.isCollapsed; diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalog.model.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalog.model.ts index 7fe3dec15..72cc38009 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalog.model.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalog.model.ts @@ -1,6 +1,8 @@ -import {CatalogItem} from './catalogItem.model'; +import {ICatalogItem} from './catalogItem.model'; -export class Catalog { - constructor(public pageIndex: number, public data: CatalogItem[], public pageSize: number, public count: number) { - } +export interface ICatalog { + pageIndex: number + data: ICatalogItem[] + pageSize: number + count: number } diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalogBrand.model.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalogBrand.model.ts new file mode 100644 index 000000000..3f7a183da --- /dev/null +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalogBrand.model.ts @@ -0,0 +1,4 @@ +export interface ICatalogBrand { + id: number + brand: string +} \ No newline at end of file diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalogItem.model.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalogItem.model.ts index c89193e20..521df03a7 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalogItem.model.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalogItem.model.ts @@ -1,3 +1,11 @@ -export class CatalogItem { - constructor(public Id: string, public Name: string, public Description: string, public Price: number, public PictureUri: string, public CatalogBrandId: number, public CatalogBrand: string, public CatalogTypeId: number, public CatalogType: string) { } +export interface ICatalogItem { + id: string; + name: string; + description: string; + price: number; + pictureUri: string; + catalogBrandId: number; + catalogBrand: string; + catalogTypeId: number; + catalogType: string; } diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalogType.model.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalogType.model.ts new file mode 100644 index 000000000..53a2a2ad3 --- /dev/null +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/catalogType.model.ts @@ -0,0 +1,4 @@ +export interface ICatalogType { + id: number + type: string +} \ No newline at end of file diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/operation-result.model.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/operation-result.model.ts deleted file mode 100644 index 6a98bfafa..000000000 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/operation-result.model.ts +++ /dev/null @@ -1,3 +0,0 @@ -export class OperationResult { - constructor(public succeeded: boolean, public message: string) { } -} diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/pager.model.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/pager.model.ts new file mode 100644 index 000000000..7d10b271b --- /dev/null +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/pager.model.ts @@ -0,0 +1,6 @@ +export interface IPager { + itemsPage: number, + totalItems: number, + actualPage: number, + totalPages: number +} \ No newline at end of file diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/user.model.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/user.model.ts deleted file mode 100644 index 7b1dbbc9c..000000000 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/models/user.model.ts +++ /dev/null @@ -1,4 +0,0 @@ -export class User { - constructor(public displayName: string, public roles: string[]) { - } -} diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/auth.service.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/auth.service.ts deleted file mode 100644 index 2f3d8ed64..000000000 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/auth.service.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Router } from '@angular/router'; - -import { DataService } from './data.service'; -import { User } from '../models/user.model'; - -@Injectable() -export class AuthService { - - constructor(private router: Router) { } - - logout() { - sessionStorage.clear(); - this.router.navigate(['/login']); - } - - isLoggedIn(): boolean { - return this.user(undefined) !== undefined; - } - - user(user: User): User { - if (user) { - sessionStorage.setItem('user', JSON.stringify(user)); - } - let userData = JSON.parse(sessionStorage.getItem('user')); - if (userData) { - user = new User(userData.displayName, userData.roles); - } - return user ? user : undefined; - } - - setAuth(res: any): void { - if (res && res.user) { - sessionStorage.setItem('user', JSON.stringify(res.user)); - } - } -} diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/data.service.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/data.service.ts index 8fca8fe26..d1e609e9e 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/data.service.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/services/data.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@angular/core'; import { Http, Response, RequestOptionsArgs, RequestMethod, Headers } from '@angular/http'; +import 'rxjs/Rx'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/throw'; import { Observer } from 'rxjs/Observer'; @@ -10,16 +11,17 @@ import 'rxjs/add/operator/catch'; @Injectable() export class DataService { - constructor(public http: Http) { } + constructor(private http: Http) { } - get(url: string, params?: any) { + get(url: string, params?: any): Observable { let options: RequestOptionsArgs = {}; options.headers = new Headers(); this.addCors(options); - return this.http.get(url, options).map(((res: Response) => { - return res.json(); - })).catch(this.handleError); + return this.http.get(url, options).map( + (res: Response) => { + return res; + }).catch(this.handleError); } post(url: string, data: any, params?: any) { @@ -42,6 +44,6 @@ export class DataService { } return Observable.throw(errMessage); } - return Observable.throw(error || 'Node.js server error'); + return Observable.throw(error || 'server error'); } } diff --git a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/shared.module.ts b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/shared.module.ts index 67b80ed8a..9c9395572 100644 --- a/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/shared.module.ts +++ b/src/Web/WebSPA/eShopOnContainers.WebSPA/Client/modules/shared/shared.module.ts @@ -16,10 +16,12 @@ import { HeaderComponent } from './layout/header.component'; import { FooterComponent } from './layout/footer.component'; // Services import { DataService } from './services/data.service'; -import { AuthService } from './services/auth.service'; import { UtilityService } from './services/utility.service'; import { UppercasePipe } from './pipes/uppercase.pipe'; +//Components: +import {Pager } from './components/pager/pager'; + @NgModule({ imports: [ CommonModule, @@ -39,7 +41,8 @@ import { UppercasePipe } from './pipes/uppercase.pipe'; FooterComponent, HeaderComponent, PageHeadingComponent, - UppercasePipe + UppercasePipe, + Pager ], exports: [ // Modules @@ -56,7 +59,8 @@ import { UppercasePipe } from './pipes/uppercase.pipe'; FooterComponent, HeaderComponent, PageHeadingComponent, - UppercasePipe + UppercasePipe, + Pager ] }) @@ -66,7 +70,6 @@ export class SharedModule { ngModule: SharedModule, providers: [ // Providers - AuthService, DataService, FormControlService, UtilityService