ngrx入门
一、构建产品管理基础
1、构建产品对象 product.ts
ng g class example/model/product.model
修改product.model.ts为
export class Product {
constructor(
public id?: number,
public name?: string,
public category?: string,
public description?: string,
public price?: number
) { }
}
2、构建数据源
ng g class example/model/rest.datasource
rest.datasource.ts文件为
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs";
import { Product } from "./product.model";
const PROTOCOL = "http";
const PORT = 3500;
@Injectable()
export class RestDataSource {
baseUrl: string;
auth_token: string;
constructor(private http: HttpClient) {
this.baseUrl = `${PROTOCOL}://${location.hostname}:${PORT}/`;
}
//获取全部产品数据
getProducts(): Observable<Product[]> {
return this.http.get<Product[]>(this.baseUrl + "products");
}
//保存产品数据
saveProduct(product: Product): Observable<Product> {
return this.http.post<Product>(this.baseUrl + "products",product);
}
//修改产品数据
updateProduct(product): Observable<Product> {
return this.http.put<Product>(this.baseUrl + "products", product);
}
//删除指定id的产品数据
deleteProduct(id: number): Observable<Product> {
return this.http.delete<Product>(`${this.baseUrl}products/${id}`);
}
}
3、构建产品仓库
ng g class example/model/product.repository
修改product.repository.ts为
import { Injectable } from "@angular/core";
import { Product } from "./product.model";
import { RestDataSource } from "./rest.datasource";
@Injectable()
export class ProductRepository {
private products: Product[]=[];
private categories: string[]=[];
constructor(private dataSource: RestDataSource) {
dataSource.getProducts().subscribe(data => {
this.products = data;
this.categories = data.map(p => p.category)
.filter((c, index, array) => array.indexOf(c) == index).sort() as string[];
});
}
getProducts(category?: string): Product[] {
return this.products
.filter(p => category == null || category == p.category);
}
getProduct(id: number): Product {
let product = this.products.find(p => p.id == id);
return product;
}
getCategories(): string[] {
return this.categories;
}
saveProduct(product: Product) {
if (product.id == null || product.id == 0) {
this.dataSource.saveProduct(product)
.subscribe(p => this.products.push(p));
} else {
this.dataSource.updateProduct(product)
.subscribe(() => {
this.products.splice(this.products.
findIndex(p => p.id == product.id), 1, product);
});
}
}
deleteProduct(id: number) {
this.dataSource.deleteProduct(id).subscribe(p => {
this.products.splice(this.products.
findIndex(() => p.id == id), 1);
})
}
}
二、构建产品相关组件
1、构建产品列表组件
ng g c example/containers/product/productTable -m example
2、构建产品编辑组件
ng g c example/containers/product/productEditor -m example
3、修改example模块的路由
example-routing.module.ts
import { NgModule } from '@angular/core';
import { FormsModule } from "@angular/forms";
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { ExampleRoutingModule } from './example-routing.module';
import { CounterComponent } from './containers/counter/counter.component';
import { StoreModule } from '@ngrx/store';
import { reducers } from './reducer';
import {RestDataSource} from './model/rest.datasource';
import {ProductRepository} from './model/product.repository';
import { ProductTableComponent } from './containers/product/product-table/product-table.component';
import { ProductEditorComponent } from './containers/product/product-editor/product-editor.component';
@NgModule({
declarations: [CounterComponent, ProductTableComponent, ProductEditorComponent],
imports: [
FormsModule,
CommonModule,
HttpClientModule, //必须引入,否则http无效
ExampleRoutingModule,
StoreModule.forFeature('example', reducers), // 挂在在state上
],
providers:[
RestDataSource,ProductRepository
]
})
export class ExampleModule { }
4、修改根组件的html,增加导航
app.component.html
<div class="container-fluid">
<div class="row">
<div class="col bg-dark text-white">
<a class="navbar-brand">ngrx入门</a>
</div>
</div>
<div class="row mt-2">
<div class="col-3">
<button class="btn btn-outline-info btn-block" routerLink="/example/products" routerLinkActive="active">
Products
</button>
<button class="btn btn-outline-info btn-block" routerLink="/example/counter" routerLinkActive="active">
计算器
</button>
</div>
<div class="col-9">
<router-outlet></router-outlet>
</div>
</div>
</div>
5、修改产品列表
product-table.component.ts
import { Component, OnInit } from '@angular/core';
import { Product } from "src/app/example/model/product.model";
import { ProductRepository } from "src/app/example/model/product.repository";
@Component({
selector: 'app-product-table',
templateUrl: './product-table.component.html',
styleUrls: ['./product-table.component.css']
})
export class ProductTableComponent implements OnInit {
constructor(private repository: ProductRepository) {
}
ngOnInit(): void {
}
getProducts(): Product[] {
return this.repository.getProducts();
}
deleteProduct(id: number) {
this.repository.deleteProduct(id);
}
}
product-table.component.html
<table class="table table-sm table-striped">
<thead>
<tr>
<th>ID</th><th>Name</th><th>Category</th><th>Price</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let p of getProducts()">
<td>{{p.id}}</td>
<td>{{p.name}}</td>
<td>{{p.category}}</td>
<td>{{p.price | currency:"USD":"symbol":"2.2-2"}}</td>
<td>
<button class="btn btn-sm btn-warning m-1"
[routerLink]="['/example/products/edit', p.id]">
Edit
</button>
<button class="btn btn-sm btn-danger" (click)="deleteProduct(p.id)">
Delete
</button>
</td>
</tr>
</tbody>
</table>
<button class="btn btn-primary" routerLink="/example/products/create">
Create New Product
</button>
6、修改产品编辑
product-editor.component.ts
import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { Product } from 'src/app/example/model/product.model';
import { ProductRepository } from 'src/app/example/model/product.repository';
@Component({
selector: 'app-product-editor',
templateUrl: './product-editor.component.html',
styleUrls: ['./product-editor.component.css']
})
export class ProductEditorComponent implements OnInit {
editing: boolean = false;
product: Product = new Product();
constructor(private repository: ProductRepository,
private router: Router,
activeRoute: ActivatedRoute) {
this.editing = activeRoute.snapshot.params["mode"] == "edit";
if (this.editing) {
Object.assign(this.product,
repository.getProduct(activeRoute.snapshot.params["id"]));
console.log("id = "+ activeRoute.snapshot.params["id"]);
console.log(JSON.stringify(this.product));
}
}
save(form: NgForm) {
this.repository.saveProduct(this.product);
this.router.navigateByUrl("/example/products");
}
ngOnInit(): void {
}
}
product-editor.component.html
<div class="bg-primary p-2 text-white" [class.bg-warning]="editing"
[class.text-dark]="editing">
<h5>{{editing ? "Edit" : "Create"}} Product</h5>
</div>
<form novalidate #form="ngForm" (ngSubmit)="save(form)">
<div class="form-group">
<label>Name</label>
<input class="form-control" name="name" [(ngModel)]="product.name" />
</div>
<div class="form-group">
<label>Category</label>
<input class="form-control" name="category" [(ngModel)]="product.category" />
</div>
<div class="form-group">
<label>Description</label>
<textarea class="form-control" name="description"
[(ngModel)]="product.description">
</textarea>
</div>
<div class="form-group">
<label>Price</label>
<input class="form-control" name="price" [(ngModel)]="product.price" />
</div>
<button type="submit" class="btn btn-primary m-1" [class.btn-warning]="editing">
{{editing ? "Save" : "Create"}}
</button>
<button type="reset" class="btn btn-secondary" routerLink="/example/products">
Cancel
</button>
</form>
product-editor.component.css
input.ng-dirty.ng-invalid { border: 2px solid #ff0000 }
input.ng-dirty.ng-valid { border: 2px solid #6bc502 }
三、运行
完美,如计划一般的完美
代码参看:
https://gitee.com/lxhjh2015/ngrx/tree/step3/
或者
git clone -b step3 https://gitee.com/lxhjh2015/ngrx.git