网络请求数据的方式改造项目
新建配置文件proxy.conf.json
{
"/api":{
"target":"http://localhost:8000"
}
}
修改package.json
"start": "ng serve --proxy-config proxy.conf.json",
我们要把原来的项目中使用的模拟数据,全部放到服务器端,使用http请求进行获取。
首先改造商品列表组件product.service.ts
import {Injectable} from '@angular/core';
import {Observable} from "rxjs";
import {HttpClient,HttpParams} from "@angular/common/http";
import 'rxjs/Rx';
@Injectable({
providedIn:'root'
})
export class ProductService {
constructor(private http:HttpClient) {
}
getAllCategories():string[]{
return ["电子产品", "硬件设备", "其他"];
}
getProducts():any{
return this.http.get("/api/products");
}
getProduct(id: string):any {
const params = new HttpParams()
.set('id', id);
return this.http.get("/api/products/",{params});
}
getCommentsForProductId(id: string):any {
const params = new HttpParams()
.set('id', id+"/comments");
return this.http.get("/api/products/",{params});
}
}
export class Product {
constructor(public id: number,
public title: string,
public price: number,
public rating: number,
public desc: string,
public categories: Array<string>) {
}
}
export class Comment {
constructor(public id: number,
public productId: number,
public timestamp: string,
public user: string,
public rating: number,
public content: string) {
}
}
改造服务端auction_server.js
"use strict";
var express = require("express");
var ws_1 = require('ws');
var app = express();
app.get('/', function (req, res) {
res.send("Hello Express");
});
app.get('/api/products', function (req, res) {
res.json(products);
});
app.get('/api/product/:id', function (req, res) {
res.json(products.find(function (product) { return product.id == req.params.id; }));
});
app.get('/api/product/:id/comments', function (req, res) {
res.json(comments.filter(function (comment) { return comment.productId == req.params.id; }));
});
var server = app.listen(8000, "localhost", function () {
console.log("服务器已启动,地址是:http://localhost:8000");
});
var wsServer = new ws_1.Server({ port: 8085 });
wsServer.on("connection", function (websocket) {
websocket.send("这个消息是服务器主动推送的");
websocket.on("message", function (message) {
console.log("接收到消息:" + message);
});
});
//定时给所有客户端推送消息
setInterval(function () {
if (wsServer.clients) {
wsServer.clients.forEach(function (client) {
client.send("这是定时推送");
});
}
}, 2000);
var Product = (function () {
function Product(id, title, price, rating, desc, categories) {
this.id = id;
this.title = title;
this.price = price;
this.rating = rating;
this.desc = desc;
this.categories = categories;
}
return Product;
}());
exports.Product = Product;
var Comment = (function () {
function Comment(id, productId, timestamp, user, rating, content) {
this.id = id;
this.productId = productId;
this.timestamp = timestamp;
this.user = user;
this.rating = rating;
this.content = content;
}
return Comment;
}());
exports.Comment = Comment;
var products = [
new Product(1, '第一个商品', 1.99, 3.5, "这是第一商品,asdxc奥术大师多撒", ["电子产品", "硬件设备", "其他"]),
new Product(2, '第二个商品', 2.99, 2.5, "这是第二商品,奥术大师多驱蚊器二无", ["硬件设备", "其他"]),
new Product(3, '第三个商品', 3.99, 1.5, "这是第三商品,请问驱蚊器翁群翁", ["电子产品", "硬件设备"]),
new Product(4, '第四个商品', 4.99, 2.0, "这是第四商品,切勿驱蚊器翁", ["电子产品", "其他"]),
new Product(5, '第五个商品', 5.99, 3.5, "这是第五商品,213123123", ["电子产品", "硬件设备", "其他"]),
new Product(6, '第六个商品', 6.99, 4.5, "这是第六商品,啊多少大所多多", ["电子产品", "硬件设备", "其他"])
];
var comments = [
new Comment(1, 1, "2017-02-02 22:22:22", "张三", 3, "东西不错"),
new Comment(2, 2, "2017-03-02 23:22:22", "李四", 4, "东西挺不错"),
new Comment(3, 1, "2017-04-02 24:22:22", "王五", 2, "东西不错"),
new Comment(4, 1, "2017-05-02 25:22:22", "赵六", 1, "东西还不错"),
new Comment(5, 1, "2017-06-02 26:22:22", "哈哈", 3, "东西不错"),
];
在product.component.html中把原来简单的过滤删除掉,使用async
管道自动订阅流,当数据异步请求到的时候,自动循环显示数据。
<div *ngFor="let product of products | async " class="col-md-4 col-sm-4 col-lg-4">
<div class="thumbnail">
<!--//属性绑定-->
<img [src]="imgUrl">
<div class="caption">
<h4 class="pull-right">{{product.price}}元</h4>
<h4><a [routerLink]="['/product',product.id]">{{product.title}}</a></h4>
<p>{{product.desc}}</p>
</div>
<div>
<app-stars [rating]="product.rating"></app-stars>
</div>
</div>
</div>
商品列表组件改造完毕了,我们继续改造商品详情组件
product-detail.component.ts
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from "@angular/router";
import {Product, ProductService, Comment} from "../shared/product.service";
@Component({
selector: 'app-product-detail',
templateUrl: './product-detail.component.html',
styleUrls: ['./product-detail.component.css']
})
export class ProductDetailComponent implements OnInit {
product: Product;
comments: Comment[];
newRating:number =5;
newComment:string = "";
isCommentHidden = true;
constructor(private routeInfo: ActivatedRoute,
private productService: ProductService) {
}
ngOnInit() {
let productId: number = this.routeInfo.snapshot.params["productId"];
//使用手工订阅的方式
this.productService.getProduct(productId).subscribe(
product => this.product = product
);
this.productService.getCommentsForProductId(productId).subscribe(
comments => this.comments = comments
);
}
addComment(){
let comment = new Comment(0,this.product.id,new Date().toISOString(),"someone",this.newRating,this.newComment);
this.comments.unshift(comment);
//reduce方法需要两个参数(sum,comment) => sum + comment.rating 匿名回调,0 代表初始值
//循环comments数组中的所有元素,当第一次循环的时候sum=0,comment是数组中的第一个元素。sum + comment.rating作为返回值,作为下一次循环时的sum
let sum = this.comments.reduce((sum,comment) => sum + comment.rating,0);
this.product.rating =sum / this.comments.length;
this.newComment =null;
this.newRating = 5;
this.isCommentHidden = true;
}
}
因为网络请求是异步形式的,所以当数据还有没返回的时候,product
和comments
的状态都是undefined
,因此我们做下处理,页面调用的时候需要这样{{product?.price}}
product-detail.component.html
<div class="thumbnail">
<img src="http://placehold.it/820x230">
<div>
<h4 class="pull-right">{{product?.price}}元</h4>
<h4>{{product?.title}}</h4>
<p>{{product?.desc}}</p>
</div>
<div>
<p class="pull-right">评论:{{comments?.length}}</p>
<p>
<app-stars [rating]="product?.rating"></app-stars>
</p>
</div>
</div>
<div class="well">
<div>
<button class="btn btn-success" (click)="isCommentHidden = !isCommentHidden">发表评论</button>
</div>
<div [hidden] = "isCommentHidden">
<div><app-stars [(rating)]="newRating" [readonly]="false"></app-stars></div>
<div>
<textarea [(ngModel)]="newComment"></textarea>
</div>
<div>
<button class="btn" (click)="addComment()">提交</button>
</div>
</div>
<div class="row" *ngFor="let comment of comments">
<hr>
<div class="col-md-12">
<app-stars [rating]="comment.rating"></app-stars>
<span>{{comment.user}}</span>
<span class="pull-right">{{comment.timestamp}}</span>
<p></p>
<p>{{comment.content}}</p>
</div>
</div>
</div>