Angular_与服务器通讯(项目改造以网络请求的方式获取数据)

网络请求数据的方式改造项目

新建配置文件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;
    }
}

因为网络请求是异步形式的,所以当数据还有没返回的时候,productcomments的状态都是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>

这里写图片描述

参考地址

客户端代码参考

服务器端代码参考

猜你喜欢

转载自blog.csdn.net/wtdask/article/details/81358548