【问题标题】:Angular 2 Passing data from Parent component to childAngular 2将数据从父组件传递给子组件
【发布时间】:2017-06-27 14:20:50
【问题描述】:

我正在使用输入绑定将产品从父组件传递到子组件,并且它在第一次调用子组件时工作。我希望每次在父级中修改 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[];
}

【问题讨论】:

  • 使用事件发射器并订阅服务,每次服务更新时,组件都会收到通知并相应更改。如果它是一个巨大的应用程序,请使用 ngrx 商店

标签: angular


【解决方案1】:

这里有一些对你有用的东西:

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

当我第一次开始编写 Angular 应用程序时,我遇到了类似的问题。始终将数据从父组件传递到子组件并不是编写应用程序的可管理方式。特别是如果它是一个包含太多嵌套组件的大型应用程序。

在本例中,我使用服务和事件发射器(都是 Angular 框架的一部分)为子组件和父组件提供相关数据。

改进代码的一种方法是使用 rxjs。这就是 Angular 事件发射器在幕后使用的。

更高级的解决方案是使用ngrx/store(Angular 的redux 库)。这特别适合大型应用程序。

无论您选择哪种解决方案,其想法都是有一个地方来维护应用程序的状态并避免过多地嵌套数据。

【讨论】:

  • 谢谢,Suyogya,我很感激。
【解决方案2】:

如果您希望子组件对父组件中的更改做出反应,您需要使用来自@angular/coreSimpleChange 实现ngOnChanges()。详细的文档可以在Angular - linkComponent Interaction Page上找到,但主要思想表达在两段代码中:

子组件

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

【讨论】:

    【解决方案3】:

    您可以为此利用共享服务。它可以同时包含要订阅的数据和可观察对象,以便在数据更新时收到通知。

    服务

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

    【讨论】:

      【解决方案4】:

      使用的解决方案: 在父组件中使用 @ViewChild 装饰器声明了一个变量,该变量指向子组件中的属性。

      @组件({ 选择器:'app-appliances-product-card', 模块ID:模块ID, templateUrl: '设备-产品-card.component.html' })

      export class AppliancesProductCardComponent implements OnInit{    
         products: Product[];
      
      @ViewChild(ProductCardComponent )
      private productCardComponent : ProductCardComponent;
      
         filterProduct(filter) {
           this.products = productCardComponent.product;
        }
      }
      

      【讨论】:

        【解决方案5】:

        有几种方法可以将数据从父组件传递到子组件。

        给你。

        How parent component pass the data to child component ?

        【讨论】:

          猜你喜欢
          • 2017-08-30
          • 2017-08-04
          • 2016-06-10
          • 2021-12-24
          • 1970-01-01
          • 1970-01-01
          • 2020-05-26
          • 2017-05-01
          • 2020-04-05
          相关资源
          最近更新 更多