我想传递一个对象给子组件.我什么都做了,但都没用.(角)

  • 本文关键字:一个对象 组件 angular
  • 更新时间 :
  • 英文 :


这是父组件:我将所有来自parentComponent的数据传递给了主页组件。

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);
}
}

(模板)您可以注意到,有一个click按钮,我在其中向父组件发出了这个方法,这样我就可以将它的值传递给另一个子组件。

<!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中使用任何值,为什么?

输入变量、事件发射器和RxJS使问题更加复杂。你只需要一个简单的Angular服务。

这是一个stackblitz: https://stackblitz.com/edit/angular-ivy-a6ub1h?file=src/app/app.component.html


你的父组件不需要任何typescript,它只需要通过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' },
];
}
}

我将创建一个服务来保存购物车列表中的项目,我们将有添加和删除功能。

<<p>购物车服务/strong>
@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 }}&nbsp;</span>
<button (click)="addToCart(product)">Add to Cart</button>
<br />
</ng-container>

购物车组件显示购物车项目并可以删除它们

<<p>购物车列表/strong>
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 }}&nbsp;</span>
<button (click)="delete(i)">Delete</button>
<br />
</ng-container>

在组件之间进行数据通信的最佳方式是使用服务,它将有助于避免您所面临的这类问题

我建议创建一个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)
}

如果你想知道为什么你在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,这将简化一切。孩子比;父母沟通。

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);

我还建议使用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([]);
}
}

另外,为了帮助确保没有人获得产品数组并在任何地方更改它,它被类型为只读数组。当你只是想要快速时,你会发现这很烦人,但是让你的数组不可变将保护你免受整个类别的潜在错误。

相关内容

最新更新