這是父組件:我將所有資料從父組件傳遞到主頁組件。
import { Component, OnInit } from '@angular/core';
import { Product } from '../Model/Product';
import { ProductService } from '../ProductsService/product.service';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css'],
})
export class ParentComponent implements OnInit {
products: Product[] = [];
cartList: Product[] = [];
constructor(private productService: ProductService) {
this.products = this.productService.getProducts();
}
ngOnInit(): void {}
addCart(product: Product) {
this.cartList.push(product);
}
}
(模板)
<app-main-page [products]="products" (addCart)="addCart($event)"></app-main-page>
<app-cart-list [cartList]="cartList"></app-cart-list>
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { ProductService } from '../../ProductsService/product.service';
import { Product } from '../../Model/Product';
@Component({
selector: 'app-main-page',
templateUrl: './main-page.component.html',
styleUrls: ['./main-page.component.css'],
})
export class MainPageComponent {
@Input() products: Product[] = [];
@Output() addCart: EventEmitter<Product> = new EventEmitter();
constructor(private productService: ProductService) {
this.products = this.productService.getProducts();
}
addToCartList(product: Product) {
this.addCart.emit(product);
console.log(product);
}
}
(模板)您可以注意到有一個單擊按鈕,在該按鈕中我將此方法發送給父組件,因此我可以將其值傳遞給另一個子組件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<section>
<div class="products">
<ul *ngFor="let product of products">
<img src="{{ product.img }}" alt="store pictures" />
<li>{{ product.name }}</li>
<li>{{ product.type }}</li>
<li>{{ product.available }}</li>
<li>{{ product.price }}</li>
<button (click)="addToCartList(product)">Add to Cart</button>
</ul>
</div>
</section>
</body>
</html>
import { Component, Input, OnInit } from '@angular/core';
import { Product } from 'src/app/Model/Product';
@Component({
selector: 'app-cart-list',
templateUrl: './cart-list.component.html',
styleUrls: ['./cart-list.component.css'],
})
export class CartListComponent implements OnInit {
constructor() {
console.log(this.cartList);
}
@Input() cartList: Product[] = [];
ngOnInit(): void {}
}
我不能在 cartList 中使用任何值,為什么?
uj5u.com熱心網友回復:
輸入變數、事件發射器和 RxJS 只是使這里的問題復雜化。你所需要的只是一個簡單的 Angular 服務。
這是一個堆疊閃電戰:https ://stackblitz.com/edit/angular-ivy-a6ub1h?file=src/app/app.component.html
您的父組件不需要任何打字稿,它需要做的就是通過 html 實體化其他組件:
父組件
<app-main-page></app-main-page>
<app-cart-list></app-cart-list>
我會做一個產品服務來模擬你的應用程式,雖然我不確定你的服務到底是什么樣子。為簡單起見,產品只會有一個名稱。
產品服務
export type Product = {
name: string;
};
@Injectable({ providedIn: 'root' })
export class ProductService {
getProducts(): Product[] {
return [
{ name: 'product1' },
{ name: 'product2' },
{ name: 'product3' },
{ name: 'product4' },
{ name: 'product5' },
{ name: 'product6' },
{ name: 'product7' },
{ name: 'product8' },
];
}
}
我將提供一項服務來保存購物車串列項,我們將擁有添加和洗掉功能。
購物車服務
@Injectable({ providedIn: 'root' })
export class CartService {
cartList: Product[] = [];
addToCart(product: Product) {
this.cartList.push(product);
}
deleteFromCart(index: number) {
this.cartList.splice(index, 1);
}
}
主頁只是獲取產品并可以將它們添加到購物車。
主頁
export class MainPageComponent implements OnInit {
products: Product[] = [];
constructor(
private prodService: ProductService,
private cartService: CartService
) {}
ngOnInit() {
this.products = this.prodService.getProducts();
}
addToCart(product: Product) {
this.cartService.addToCart(product);
}
}
<h1>Main Page</h1>
<ng-container *ngFor="let product of products">
<span>{{ product.name }} </span>
<button (click)="addToCart(product)">Add to Cart</button>
<br />
</ng-container>
購物車組件顯示購物車專案并可以洗掉它們
購物車清單
export class CartListComponent {
constructor(private cartService: CartService) {}
get cartList() {
return this.cartService.cartList;
}
delete(index: number) {
this.cartService.deleteFromCart(index);
}
}
<h1>Cart</h1>
<ng-container *ngFor="let product of cartList; index as i">
<span>{{ product.name }} </span>
<button (click)="delete(i)">Delete</button>
<br />
</ng-container>
uj5u.com熱心網友回復:
在組件之間進行資料通信的最佳方式是使用服務,這將有助于避免您面臨的此類問題
我建議你創建一個 CartService:
@Injectable()
export class CartService {
cart$ = new BehaviorSubject<Product[]>([]);
add(product: Product) {
this.cart$.pipe(take(1)).subscribe(items => {
this.cart$.next([...items, product])
})
}
clear() {
this.cart$.next([])
}
}
然后從購物車組件將購物車移植到其視圖:
cart$ = this.cartService.cart$
并更新您的視圖以處理購物車專案:
<ul *ngFor="let product of cart$ | async">
<img src="{{ product.img }}" />
<li>{{ product.name }}</li>
<li>{{ product.type }}</li>
<li>{{ product.available }}</li>
<li>{{ product.price }}</li>
</ul>
從 products 組件中,您應該將addToCartList功能更改為:
addToCartList(product) {
this.cartService.add(product)
}
uj5u.com熱心網友回復:
如果您想知道為什么在CartListComponent控制臺日志中看到一個空陣列,那是因為組件的輸入是在組件初始化和constructor之前的運行期間設定的。因此,如果您想檢查是否設定正確,您應該在鉤子@Input() cartList中將其注銷:OnInit
export class CartListComponent implements OnInit {
@Input() cartList: Product[] = [];
ngOnInit(): void {
console.log(this.cartList);
}
}
您也可以使用setter來記錄它
而且我認為當您嘗試將商品添加到購物車時,您的組件很有可能無法正確重新渲染,因為當涉及到陣列或物件時@Input,Angular 通過比較它們的參考而不是值來檢測更改。因此,當您執行時this.cartList.push(product),您不會更改陣列參考,而是更改其值。為了解決這個問題,您可以嘗試通過復制舊陣列來為變數分配一個全新的陣列
this.cartList.push(product);
this.cartList = [...this.cartList];
解決此問題的更好方法是創建一個CartService. 這將通過將購物車周圍的邏輯集中到一個地方來簡化一切,而不是試圖創建一個混亂的 Parent -> Child -> Parent 通信。
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
interface Product {}
interface Cart {
items: Product[];
someOtherProperty?: any;
}
@Injectable({
providedIn: 'root',
})
export class CartService {
private _cartSubject: BehaviorSubject<Cart> = new BehaviorSubject<Cart>({
items: [],
});
cart$: Observable<Cart> = this._cartSubject.asObservable();
addToCart(item: Product) {
const oldCart: Cart = this._cartSubject.getValue();
const newCart: Cart = { ...oldCart, items: [...oldCart.items, item] };
this._cartSubject.next(newCart);
}
}
下一步就是在你的組件中注入和使用服務:constructor(private cartService: CartService){}
- 要訪問購物車專案串列:
cartItems$ = this.cartService.cart$.pipe(map((cart) => cart.items));
- 要將東西添加到購物車:
this.cartService.add(someProduct);
uj5u.com熱心網友回復:
我還建議使用 CartService,并且正在采納 The Fabio 的建議,以提供一個不會暴露Subject.next在允許的邏輯之外的更好的答案。例如,您可能想要更改CartService以確保產品陣列永遠不會包含重復項,并且您不能保證任何消費代碼都可以通過Subject.next!
// Imutable array of Product objects
type Products = ReadonlyArray<Readonly<Product>>;
@Injectable()
export class CartService {
private _products$: BehaviorSubject<Products> = new BehaviorSubject([]);
readonly products$ = this._products$.asObservable();
addProduct(product: Product) {
// A new, readonly array object
const products: Products = [
...this._products$.getValue(),
product
];
this._products$.next(products);
return products;
}
clear(): void {
this._products$.next([]);
}
}
此外,為了幫助確保沒有人獲得產品陣列并隨處更改它,它被鍵入為只讀陣列。當您只想快點時,您會發現這很煩人,但是使您的陣列不可變將保護您免受各種潛在錯誤的影響。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/491834.html
標籤:有角度的
