[英]Angular 2 Passing data from Parent component to child
我使用输入绑定将产品从父组件传递到子组件,它在第一次调用子组件时工作。 我希望每次在父级中修改时,对filterProduct()中的产品的更改都会反映在子级中,但这种情况不会发生。 我该如何实现这一目标。
父模板:
<div class="container-fluid">
<div class="col-sm-9">
<app-product-card [products]=products></app-product-card>
</div>
父组件:
@Component({
selector: 'app-appliances-product-card',
moduleId: module.id,
templateUrl: 'appliances-product-card.component.html'
})
export class AppliancesProductCardComponent implements OnInit{
products: Product[];
filterProduct(filter) {
this.products = this.filteredProducts;
}
}
子组件:
@Component({
selector: 'app-product-card',
moduleId: module.id,
templateUrl: 'product-card.component.html'
})
export class ProductCardComponent {
@Input() products: Product[];
}
以下是可能对您有用的东西:
https://plnkr.co/edit/S47fBh2xdT1gp2zrznk4?p=preview
父代组件和子组件都将使用服务来获取数据,而不是将数据从父组件传递到子组件。
父组件:
import { Component, OnInit } from '@angular/core';
import { Product } from './product'
import { ProductsService } from './products.service';
@Component({
selector: 'app-appliances-product-card',
template: `
<div class="container-fluid">
<button (click)="filterProduct('Type 1')">Filter Type 1</button>
<button (click)="filterProduct('')">Clear Filter</button>
<div class="col-sm-9">
<app-products-card></app-products-card>
</div>
</div>
`
})
export class AppliancesProductCardComponent implements OnInit {
products: Product[];
constructor(private _productsService: ProductsService){ }
filterProduct(type: string) {
this.products = this._productsService.filterProduct(type);
}
ngOnInit() {
this.products = this._productsService.getAllProducts();
}
}
子组件:
import { Component, OnInit, Input } from '@angular/core';
import { Product } from './product';
import { ProductsService } from './products.service';
@Component({
selector: 'app-products-card',
template: `
<h1>Product Card</h1>
<div *ngFor="let product of products">{{product.name}} - {{product.type}}</div>
`
})
export class ProductsCardComponent implements OnInit {
constructor(private _productsService: ProductsService){ }
ngOnInit() {
this.products = this._productsService.getAllProducts();
this._productsService.filteredProducts.subscribe(products => {
console.log(products);
this.products = products
});
}
}
服务:
import { EventEmitter, Injectable } from '@angular/core';
import { Product } from './product';
export class ProductsService {
filteredProducts = new EventEmitter<Product[]>;
private products: Product[] = [
{ id: 1, name: 'Product 1', price: 10.50, type: 'Type 1' },
{ id: 2, name: 'Product 2', price: 15.50, type: 'Type 1' },
{ id: 3, name: 'Product 3', price: 1.50, type: 'Type 2' },
{ id: 4, name: 'Product 4', price: 100.50, type: 'Type 3' }
];
getAllProducts(): Product[] {
return this.products.slice();
}
filterProduct(type: string): Product[]{
let filteredProducts = this.products.filter(p => !type || p.type == type).slice();
this.filteredProducts.emit(filteredProducts);
}
}
我第一次开始编写角度应用程序时遇到了类似的问题。 始终将数据从父组件传递到子组件不是编写应用程序的可管理方式。 特别是如果它是一个包含太多嵌套组件的大应用程序。
在这个例子中,我使用服务和事件发射器(角度框架的一部分)来向子组件和父组件提供相关数据。
改进代码的一种方法是使用rxjs。 这是角度事件发射器在场景后面使用的。
更高级的解决方案是使用ngrx / store(针对Angular的redux库)。 这特别适用于大型应用。
无论您选择哪种解决方案,我们的想法都是有一个地方来维护应用程序的状态并避免过多地嵌套数据。
如果您希望子组件对父组件中的更改做出反应,则需要使用@angular/core
SimpleChange
实现ngOnChanges()
。 可以在Angular - linkComponent Interaction页面上找到详细的文档,但主要思想体现在两个代码块中:
子组件
import { Component, Input, OnChanges, SimpleChange } from '@angular/core';
@Component({
selector: 'version-child',
template: `
<h3>Version {{major}}.{{minor}}</h3>
<h4>Change log:</h4>
<ul>
<li *ngFor="let change of changeLog">{{change}}</li>
</ul>
`
})
export class VersionChildComponent implements OnChanges {
@Input() major: number;
@Input() minor: number;
changeLog: string[] = [];
ngOnChanges(changes: {[propKey: string]: SimpleChange}) {
let log: string[] = [];
for (let propName in changes) {
let changedProp = changes[propName];
let to = JSON.stringify(changedProp.currentValue);
if (changedProp.isFirstChange()) {
log.push(`Initial value of ${propName} set to ${to}`);
} else {
let from = JSON.stringify(changedProp.previousValue);
log.push(`${propName} changed from ${from} to ${to}`);
}
}
this.changeLog.push(log.join(', '));
}
}
父组件
import { Component } from '@angular/core';
@Component({
selector: 'version-parent',
template: `
<h2>Source code version</h2>
<button (click)="newMinor()">New minor version</button>
<button (click)="newMajor()">New major version</button>
<version-child [major]="major" [minor]="minor"></version-child>
`
})
export class VersionParentComponent {
major = 1;
minor = 23;
newMinor() {
this.minor++;
}
newMajor() {
this.major++;
this.minor = 0;
}
}
您可以利用共享服务。 它可以包含要订阅的数据和可观察数据,以便在更新数据时得到通知。
服务
export class ListService {
list1Event: EventEmitter<any> = new EventEmitter();
getLists() {
return this.http.get(url).map(res => res.json())
.subscribe(
(data) => {
this.list1Event.emit(data.list1);
}
);
}
}
零件
@Component({
selector: 'my-component1',
template: `
<ul>
<li *ngFor="#item of list">{{item.name}}</li>
</ul>
`
})
export class MyComponent1 {
constructor(private service:ListService) {
this.service.list1Event.subscribe(data => {
this.list = data;
});
}
}
解决方案:使用父组件中的@ViewChild装饰器声明一个变量,该装饰符指向子组件中的属性。
@Component({selector:'app-appliances-product-card',moduleId:module.id,templateUrl:'appliances-product-card.component.html'})
export class AppliancesProductCardComponent implements OnInit{
products: Product[];
@ViewChild(ProductCardComponent )
private productCardComponent : ProductCardComponent;
filterProduct(filter) {
this.products = productCardComponent.product;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.