Angular 管理數(shù)據(jù)

2022-06-28 09:54 更新

管理數(shù)據(jù)

本章基于以一個(gè)基本 Angular 應(yīng)用快速上手的第二步 —— 添加導(dǎo)航。 在此開(kāi)發(fā)階段,本商店應(yīng)用具有一個(gè)包含兩個(gè)視圖的商品名錄:商品列表和商品詳情。用戶點(diǎn)擊清單中的某個(gè)商品名稱,就會(huì)在新視圖中看到具有專(zhuān)門(mén)的 URL 或路由的詳情頁(yè)。

本頁(yè)將指導(dǎo)你分三個(gè)步驟創(chuàng)建購(gòu)物車(chē):

  • 修改商品詳情視圖,讓它包含一個(gè) “Buy” 按鈕,它會(huì)把當(dāng)前商品添加到由 "購(gòu)物車(chē)服務(wù)" 管理的商品列表中。
  • 添加一個(gè)購(gòu)物車(chē)組件,它會(huì)顯示購(gòu)物車(chē)中的商品。
  • 添加一個(gè)配送組件,它會(huì)使用 Angular 的 ?HttpClient ?從 ?.json? 文件中檢索配送數(shù)據(jù)來(lái)取得購(gòu)物車(chē)中這些商品的運(yùn)費(fèi)。

創(chuàng)建購(gòu)物車(chē)服務(wù)

在 Angular 中, 服務(wù)是類(lèi)的一個(gè)實(shí)例, 借助 Angular 的依賴注入體系,你可以在應(yīng)用中的任意部分使用它。

現(xiàn)在, 用戶可以瀏覽產(chǎn)品信息,而應(yīng)用可以模擬分享產(chǎn)品,以及發(fā)出產(chǎn)品變更通知。

下一步是為用戶提供一種把產(chǎn)品添加到購(gòu)物車(chē)中的方法。 本章節(jié)將帶領(lǐng)你添加一個(gè) Buy 按鈕并且建立一個(gè)購(gòu)物車(chē)服務(wù)以保存購(gòu)物車(chē)中的產(chǎn)品信息。

定義購(gòu)物車(chē)服務(wù)

本節(jié)將引導(dǎo)你創(chuàng)建用于跟蹤添加到購(gòu)物車(chē)的產(chǎn)品的 ?CartService ?。

  1. 在終端中通過(guò)運(yùn)行以下命令生成一個(gè)新的 ?cart ?服務(wù):
  2. ng generate service cart
  3. 將 ?Product ?接口從 ?./products.ts? 導(dǎo)入到 ?cart.service.ts? 文件中,在 ?CartService ?類(lèi)中,定義一個(gè) ?items ?屬性來(lái)存儲(chǔ)購(gòu)物車(chē)中當(dāng)前產(chǎn)品的數(shù)組。
  4. import { Product } from './products';
    /* . . . */
    export class CartService {
      items: Product[] = [];
    /* . . . */
    }
  5. 定義把商品添加到購(gòu)物車(chē)、返回購(gòu)物車(chē)商品以及清除購(gòu)物車(chē)商品的方法:
  6. export class CartService {
      items: Product[] = [];
    /* . . . */
    
      addToCart(product: Product) {
        this.items.push(product);
      }
    
      getItems() {
        return this.items;
      }
    
      clearCart() {
        this.items = [];
        return this.items;
      }
    /* . . . */
    }
    • ?addToCart()? 方法會(huì)將產(chǎn)品附加到 ?items ?數(shù)組中。
      • ?getItems()? 方法會(huì)收集用戶加到購(gòu)物車(chē)中的商品,并返回每個(gè)商品及其數(shù)量。
      • ?clearCart()? 方法返回一個(gè)空數(shù)組。

使用購(gòu)物車(chē)服務(wù)

本節(jié)會(huì)教你使用 ?CartService ?來(lái)把一個(gè)商品添加到購(gòu)物車(chē)中。

  1. 在 ?product-details.component.ts? 中導(dǎo)入購(gòu)物車(chē)服務(wù)。
  2. import { Component, OnInit } from '@angular/core';
    import { ActivatedRoute } from '@angular/router';
    
    import { Product, products } from '../products';
    import { CartService } from '../cart.service';
    • 通過(guò)把購(gòu)物車(chē)服務(wù)注入到這里的 ?constructor()? 中來(lái)注入它。
    • export class ProductDetailsComponent implements OnInit {
      
        constructor(
          private route: ActivatedRoute,
          private cartService: CartService
        ) { }
      }
  3. 定義 ?addToCart()? 方法,該方法會(huì)當(dāng)前商品添加到購(gòu)物車(chē)中。
  4. export class ProductDetailsComponent implements OnInit {
    
      addToCart(product: Product) {
        this.cartService.addToCart(product);
        window.alert('Your product has been added to the cart!');
      }
    }

    ?addToCart()? 方法做了如下事情:

    • 以當(dāng)前'product'作為參數(shù)。
    • 使用 ?CartService ??addToCart()? 方法去添加產(chǎn)品到購(gòu)物車(chē)中。
    • 顯示一條你已經(jīng)添加了一個(gè)產(chǎn)品到購(gòu)物車(chē)到消息。
  5. 在 ?product-details.component.html? 中,添加一個(gè)帶有 Buy 標(biāo)簽的按鈕,并且把其 ?click()? 事件綁定到 ?addToCart()? 方法上。 這段代碼會(huì)為產(chǎn)品詳情模板添加一個(gè) Buy 按鈕,并把當(dāng)前產(chǎn)品添加到購(gòu)物車(chē)中。
  6. <h2>Product Details</h2>
    
    <div *ngIf="product">
      <h3>{{ product.name }}</h3>
      <h4>{{ product.price | currency }}</h4>
      <p>{{ product.description }}</p>
      <button (click)="addToCart(product)">Buy</button>
    </div>
  7. 刷新應(yīng)用,以驗(yàn)證新的 ?Buy ?按鈕如預(yù)期般出現(xiàn)了,并且單擊某個(gè)產(chǎn)品的名稱,以展示其詳情。

  8. 點(diǎn)擊“Buy”按鈕來(lái)把該商品添加到購(gòu)物車(chē)中存儲(chǔ)的商品列表中,并顯示一條確認(rèn)消息。

創(chuàng)建購(gòu)物車(chē)視圖

為了讓顧客看到他們的購(gòu)物車(chē),你可以用兩步創(chuàng)建購(gòu)物車(chē)視圖:

  1. 創(chuàng)建一個(gè)購(gòu)物車(chē)組件并配置指向這個(gè)新組件的路由。
  2. 顯示購(gòu)物車(chē)商品

設(shè)置該組件

要?jiǎng)?chuàng)建購(gòu)物車(chē)視圖,可遵循與創(chuàng)建 ?ProductDetailsComponent ?相同的步驟,并且為這個(gè)新組件配置路由。

  1. 通過(guò)運(yùn)行以下命令在終端中生成一個(gè)名為 ?cart ?的新組件:
  2. ng generate component cart

    此命令將生成 ?cart.component.ts? 文件及其關(guān)聯(lián)的模板和樣式文件。

    import { Component } from '@angular/core';
    
    @Component({
      selector: 'app-cart',
      templateUrl: './cart.component.html',
      styleUrls: ['./cart.component.css']
    })
    export class CartComponent {
    
      constructor() { }
    
    }

    StackBlitz 還在組件中默認(rèn)生成一個(gè) ?ngOnInit()? 。對(duì)于本教程,你可以忽略 ?CartComponent ?的 ?ngOnInit()? 。

  3. 請(qǐng)注意,新創(chuàng)建的 ?CartComponent? 已添加到 ?app.module.ts? 中模塊的 ?declarations ?中。
  4. import { CartComponent } from './cart/cart.component';
    
    @NgModule({
      declarations: [
        AppComponent,
        TopBarComponent,
        ProductListComponent,
        ProductAlertsComponent,
        ProductDetailsComponent,
        CartComponent,
      ],
  5. 打開(kāi) ?app.module.ts?,為組件 ?CartComponent ?添加一個(gè)路由,其路由為 ?cart ?:
  6. @NgModule({
      imports: [
        BrowserModule,
        ReactiveFormsModule,
        RouterModule.forRoot([
          { path: '', component: ProductListComponent },
          { path: 'products/:productId', component: ProductDetailsComponent },
          { path: 'cart', component: CartComponent },
        ])
      ],
  7. 修改 "Checkout" 按鈕,以便讓它路由到 ?/cart?。 在 ?top-bar.component.html? 中添加一個(gè)指向 ?/cart? 的 ?routerLink ?指令。
  8. <a routerLink="/cart" class="button fancy-button">
      <i class="material-icons">shopping_cart</i>Checkout
    </a>
  9. 要查看新的購(gòu)物車(chē)組件,請(qǐng)點(diǎn)擊“Checkout”按鈕。你會(huì)看到默認(rèn)文本“cart works!”,該 URL 的格式為 ?https://getting-started.stackblitz.io/cart?,其中的 getting-started.stackblitz.io 部分可能與你的 StackBlitz 項(xiàng)目不同。

顯示購(gòu)物車(chē)商品

本節(jié)將告訴你如何修改購(gòu)物車(chē)組件以使用購(gòu)物車(chē)服務(wù)來(lái)顯示購(gòu)物車(chē)中的商品。

  1. 在 ?cart.component.ts? 中,從 ?cart.service.ts? 文件中導(dǎo)入 ?CartService?。
  2. import { Component } from '@angular/core';
    import { CartService } from '../cart.service';
    • 注入 ?CartService?,以便購(gòu)物車(chē)組件可以使用它。
    • export class CartComponent {
      
      
        constructor(
          private cartService: CartService
        ) { }
      }
  3. 定義 ?items ?屬性,以便把商品存放在購(gòu)物車(chē)中。
  4. export class CartComponent {
    
      items = this.cartService.getItems();
    
      constructor(
        private cartService: CartService
      ) { }
    }

    這段代碼使用 ?CartService ?的 ?getItems()? 方法來(lái)設(shè)置條目。

  5. 修改模板,加上標(biāo)題,用帶有 ?*ngFor? 的 ?<div>? 來(lái)顯示每個(gè)購(gòu)物車(chē)商品的名字和價(jià)格。
  6. 生成的 ?CartComponent ?模板如下:

    <h3>Cart</h3>
    
    <div class="cart-item" *ngFor="let item of items">
      <span>{{ item.name }}</span>
      <span>{{ item.price | currency }}</span>
    </div>
  7. 驗(yàn)證你的購(gòu)物車(chē)如預(yù)期般工作:
    • 點(diǎn)擊 My Store
    • 單擊商品名稱以顯示其詳細(xì)信息。
    • 點(diǎn)擊Buy 將商品添加到購(gòu)物車(chē)。
    • 點(diǎn)擊Checkout查看購(gòu)物車(chē)。

檢索運(yùn)費(fèi)價(jià)格

服務(wù)器通常采用流的形式返回?cái)?shù)據(jù)。 流是很有用的,因?yàn)樗鼈兛梢院苋菀椎剞D(zhuǎn)換返回的數(shù)據(jù),也可以修改你請(qǐng)求數(shù)據(jù)的方式。 Angular 的 HTTP 客戶端( ?HttpClient ?)是一種內(nèi)置的方式,可以從外部 API 中獲取數(shù)據(jù),并以流的形式提供給你的應(yīng)用。

本節(jié)會(huì)為你展示如何使用 ?HttpClient ?從外部文件中檢索運(yùn)費(fèi)。

在本指南的 StackBlitz 應(yīng)用中,通過(guò) ?assets/shipping.json? 文件提供了一些預(yù)定義的配送數(shù)據(jù)。你可以利用這些數(shù)據(jù)為購(gòu)物車(chē)中的商品添加運(yùn)費(fèi)。

[
  {
    "type": "Overnight",
    "price": 25.99
  },
  {
    "type": "2-Day",
    "price": 9.99
  },
  {
    "type": "Postal",
    "price": 2.99
  }
]

配置 AppModule 以使用 HttpClient

要使用 Angular 的 HTTP 客戶端之前,你必須先配置你的應(yīng)用來(lái)使用 ?HttpClientModule?。

Angular 的 ?HttpClientModule ?中注冊(cè)了在整個(gè)應(yīng)用中使用 ?HttpClient ?服務(wù)的單個(gè)實(shí)例所需的服務(wù)提供者。

  1. 在 ?app.module.ts? 的頂部從 ?@angular/common/http? 包中導(dǎo)入 ?HttpClientModule ?以及其它導(dǎo)入項(xiàng)。 由于有很多其它導(dǎo)入項(xiàng),因此這里的代碼片段省略它們,以保持簡(jiǎn)潔。請(qǐng)確?,F(xiàn)有的導(dǎo)入都還在原地。
  2. import { HttpClientModule } from '@angular/common/http';
  3. 把 ?HttpClientModule ?添加到 ?AppModule ??@NgModule()? 的 ?imports ?數(shù)組中,以便全局注冊(cè) Angular 的 ?HttpClient?。
  4. @NgModule({
      imports: [
        BrowserModule,
        HttpClientModule,
        ReactiveFormsModule,
        RouterModule.forRoot([
          { path: '', component: ProductListComponent },
          { path: 'products/:productId', component: ProductDetailsComponent },
          { path: 'cart', component: CartComponent },
        ])
      ],
      declarations: [
        AppComponent,
        TopBarComponent,
        ProductListComponent,
        ProductAlertsComponent,
        ProductDetailsComponent,
        CartComponent,
      ],
      bootstrap: [
        AppComponent
      ]
    })
    export class AppModule { }

配置 CartService 以使用 HttpClient

下一步是注入 ?HttpClient ?服務(wù)到你的服務(wù)中, 這樣你的應(yīng)用可以獲取數(shù)據(jù)并且與外部API和資源互動(dòng)。

  1. 從 ?@angular/common/http? 包中導(dǎo)入 ?HttpClient?。
  2. import { Injectable } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    import { Product } from './products';
  3. 把 ?HttpClient ?注入到 ?CartService ?的構(gòu)造函數(shù)中:
  4. export class CartService {
      items: Product[] = [];
    
      constructor(
        private http: HttpClient
      ) {}
    /* . . . */
    }

配置 CartService 以得到商品價(jià)格

要從 ?shapping.json? 中得到商品數(shù)據(jù), 你可以使用 ?HttpClient ??get()? 方法。

  1. 在 ?cart.service.ts? 中 ?clearCart()? 方法下面,定義一個(gè)新的 ?getShippingPrices()? 方法,該方法會(huì)調(diào)用 ?HttpClient#get() ?方法。
  2. export class CartService {
    /* . . . */
      getShippingPrices() {
        return this.http.get<{type: string, price: number}[]>('/assets/shipping.json');
      }
    }

創(chuàng)建配送組件

現(xiàn)在你的應(yīng)用已經(jīng)可以檢索配送數(shù)據(jù)了,你還要?jiǎng)?chuàng)建一個(gè)配送組件和相關(guān)的模板。

  1. 在終端窗口中運(yùn)行如下命令,以生成名為 ?shipping ?的組件:
  2. ng generate component shipping

    右鍵單擊 ?app ?文件夾,選擇 Angular Generator 和 Component 來(lái)生成一個(gè)名為 ?shipping ?的新組件。

    import { Component } from '@angular/core';
    
    @Component({
      selector: 'app-shipping',
      templateUrl: './shipping.component.html',
      styleUrls: ['./shipping.component.css']
    })
    export class ShippingComponent {
    
      constructor() { }
    
    }
  3. 在 ?app.module.ts? 中,添加一個(gè)配送路由。其 ?path ?為 ?shipping?,其 component 為 ?ShippingComponent?。
  4. @NgModule({
      imports: [
        BrowserModule,
        HttpClientModule,
        ReactiveFormsModule,
        RouterModule.forRoot([
          { path: '', component: ProductListComponent },
          { path: 'products/:productId', component: ProductDetailsComponent },
          { path: 'cart', component: CartComponent },
          { path: 'shipping', component: ShippingComponent },
        ])
      ],
      declarations: [
        AppComponent,
        TopBarComponent,
        ProductListComponent,
        ProductAlertsComponent,
        ProductDetailsComponent,
        CartComponent,
        ShippingComponent
      ],
      bootstrap: [
        AppComponent
      ]
    })
    export class AppModule { }

    新的配送組件尚未鏈接到任何其它組件,但你可以通過(guò)輸入其路由指定的 URL 在預(yù)覽窗格中看到它的模板。該 URL 具有以下模式:?https://angular-ynqttp--4200.local.webcontainer.io/shipping? ,其中的 gets-started.stackblitz.io 部分可能與你的 StackBlitz 項(xiàng)目不同。

配置 ShippingComponent 以使用 CartService

這個(gè)章節(jié)將指導(dǎo)你修改 ?ShappingComponent ?以通過(guò)HTTP從 ?shipping.json? 文件中提取商品數(shù)據(jù)。

  1. 在 ?shipping.component.ts? 中導(dǎo)入 ?CartService?。
  2. import { Component } from '@angular/core';
    
    import { CartService } from '../cart.service';
  3. 把購(gòu)物車(chē)服務(wù)注入到 ?ShippingComponent ?的 ?constructor()? 構(gòu)造函數(shù)中:
  4. constructor(private cartService: CartService) { }
    • 定義一個(gè) ?shippingCosts ?屬性,并從 ?CartService ?中利用購(gòu)物車(chē)服務(wù)的 ?getShippingPrices()? 方法設(shè)置它。
    • export class ShippingComponent {
      
        shippingCosts = this.cartService.getShippingPrices();
      }
  5. 利用 ?async ?管道修改配送組件的模板,以顯示配送類(lèi)型和價(jià)格:
  6. <h3>Shipping Prices</h3>
    
    <div class="shipping-item" *ngFor="let shipping of shippingCosts | async">
      <span>{{ shipping.type }}</span>
      <span>{{ shipping.price | currency }}</span>
    </div>

    ?async ?管道從數(shù)據(jù)流中返回最新值,并在所屬組件的生命期內(nèi)持續(xù)返回。當(dāng) Angular 銷(xiāo)毀該組件時(shí),?async ?管道會(huì)自動(dòng)停止。

  7. 在購(gòu)物車(chē)視圖中添加一個(gè)到配送視圖的鏈接:
  8. <h3>Cart</h3>
    
    <p>
      <a routerLink="/shipping">Shipping Prices</a>
    </p>
    
    <div class="cart-item" *ngFor="let item of items">
      <span>{{ item.name }}</span>
      <span>{{ item.price | currency }}</span>
    </div>
  9. 點(diǎn)擊 Checkout 按鈕,查看更新后的購(gòu)物車(chē)。注意,修改本應(yīng)用會(huì)導(dǎo)致預(yù)覽窗格刷新,這會(huì)清空購(gòu)物車(chē)。

  10. 點(diǎn)擊此鏈接可以導(dǎo)航到運(yùn)費(fèi)頁(yè)。



以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)