Angular 角度2:组件A更改时更新组件B

Angular 角度2:组件A更改时更新组件B,angular,Angular,我试图找出Angular 2中的跨组件通信,但现在失败了。基本上我有3个组件:一个AddProduct组件(在本例中为父组件)、一个CategorySelector组件(使用服务用类别列表填充下拉列表)和一个ProductSelector组件(使用类别作为参数并用属于所选类别的产品列表填充下拉列表) 我想弄清楚的是如何使CategorySelector更改时,ProductSelector运行获取新产品列表所需的函数 这是我的密码: add-product.html <h1 class="

我试图找出Angular 2中的跨组件通信,但现在失败了。基本上我有3个组件:一个AddProduct组件(在本例中为父组件)、一个CategorySelector组件(使用服务用类别列表填充下拉列表)和一个ProductSelector组件(使用类别作为参数并用属于所选类别的产品列表填充下拉列表)

我想弄清楚的是如何使CategorySelector更改时,ProductSelector运行获取新产品列表所需的函数

这是我的密码:

add-product.html

<h1 class="ui header">Add product</h1>

<form class="ui form">
  <div class="four wide field">
    <label>Category</label>
    <category-selector (selection)="setCategory($event)" defaultText="Please Choose a Category"></category-selector>
  </div>
  <div class="four wide field" *ngIf="selectedCategory">
    <label>Product</label>
    <product-selector (selection)="setProduct($event)" [category]="selectedCategory" defaultText="Select a Product"></product-selector>
  </div>
</form>
product-selector.component.ts

import {Component, OnInit, NgZone} from 'angular2/core';
import {StoreProduct} from './storeproduct.service';
import {Product} from './product.service';
import {CategorySelector} from './category-selector.component';
import {ProductSelector} from './product-selector.component';

declare var __resourcePath: string;

@Component({
    selector: 'add-product',
    templateUrl: __resourcePath + '/html/add-product.html',
    providers: [Product, StoreProduct],
    directives: [CategorySelector, ProductSelector]
})
export class AddProduct {

    public categories: string[];
    public selectedCategory: string;
    public selectedProduct: Product__c;

    constructor(private storeproduct: StoreProduct, private product: Product, private zone: NgZone) {}

    setCategory(selection: string) {
        this.selectedCategory = selection;
    }

    setProduct() {

    }

}
import {Component, Input, Output, EventEmitter, OnInit} from 'angular2/core';
import {Product} from './product.service';

@Component({
    selector: 'product-selector',
    template: `
        <select #sel (change)="selection.emit(sel.value)" class="ui fluid dropdown">
            <option value="" selected>{{defaultText}}</option>
            <option *ngFor="#product of products" value="{{product}}">{{product.Name}}</option>
        </select>
    `,
    providers: [Product]
})
export class ProductSelector implements OnInit {

    @Output() selection = new EventEmitter();
    @Input() defaultText: string = 'No product selected';
    @Input() category: string;

    private products: Product__c[];

    constructor(private product: Product) {}

  fetchProducts() {
    let source = this.product.fetch(this.category);
        let sub = source.toPromise().then((val: JSForce.SOQLQueryResult<Product__c>) => {
            this.products = val.records;
        });
  }

    ngOnInit(): any {
    this.fetchProducts();
    }

}
import {Component, Input, Output, EventEmitter, OnInit} from 'angular2/core';
import {StoreProduct} from './storeproduct.service';

@Component({
    selector: 'category-selector',
    template: `
        <form class="ui form">
            <select #sel (change)="selection.emit(sel.value)" class="ui fluid dropdown">
                <option value="" selected>{{defaultText}}</option>
                <option *ngFor="#category of categories" value="{{category}}">{{category}}</option>
            </select>
        </form>
    `,
    providers: [StoreProduct]
})
export class CategorySelector implements OnInit {

    @Output() selection = new EventEmitter();
    @Input() defaultText: string = 'No category selected';

    categories: string[];

    constructor(private sp: StoreProduct) {}

    ngOnInit(): any {

        let source = this.sp.fetchCategories();
        let sub = source.toPromise().then((val: string[]) => {
            this.categories = val;
        });
    }

}
import{Component,Input,Output,EventEmitter,OnInit}来自'angular2/core';
从“./Product.service”导入{Product};
@组成部分({
选择器:“产品选择器”,
模板:`
{{defaultText}}
{{product.Name}
`,
供应商:[产品]
})
导出类ProductSelector实现OnInit{
@Output()selection=neweventemitter();
@Input()defaultText:string='未选择任何产品';
@Input()类别:字符串;
私人产品:Product_u_c[];
构造函数(私有产品:产品){}
获取产品(){
让source=this.product.fetch(this.category);
让sub=source.toPromise().then((val:JSForce.SOQLQueryResult)=>{
this.products=val.records;
});
}
ngOnInit():任何{
这是fetchProducts();
}
}
类别选择器.component.ts

import {Component, OnInit, NgZone} from 'angular2/core';
import {StoreProduct} from './storeproduct.service';
import {Product} from './product.service';
import {CategorySelector} from './category-selector.component';
import {ProductSelector} from './product-selector.component';

declare var __resourcePath: string;

@Component({
    selector: 'add-product',
    templateUrl: __resourcePath + '/html/add-product.html',
    providers: [Product, StoreProduct],
    directives: [CategorySelector, ProductSelector]
})
export class AddProduct {

    public categories: string[];
    public selectedCategory: string;
    public selectedProduct: Product__c;

    constructor(private storeproduct: StoreProduct, private product: Product, private zone: NgZone) {}

    setCategory(selection: string) {
        this.selectedCategory = selection;
    }

    setProduct() {

    }

}
import {Component, Input, Output, EventEmitter, OnInit} from 'angular2/core';
import {Product} from './product.service';

@Component({
    selector: 'product-selector',
    template: `
        <select #sel (change)="selection.emit(sel.value)" class="ui fluid dropdown">
            <option value="" selected>{{defaultText}}</option>
            <option *ngFor="#product of products" value="{{product}}">{{product.Name}}</option>
        </select>
    `,
    providers: [Product]
})
export class ProductSelector implements OnInit {

    @Output() selection = new EventEmitter();
    @Input() defaultText: string = 'No product selected';
    @Input() category: string;

    private products: Product__c[];

    constructor(private product: Product) {}

  fetchProducts() {
    let source = this.product.fetch(this.category);
        let sub = source.toPromise().then((val: JSForce.SOQLQueryResult<Product__c>) => {
            this.products = val.records;
        });
  }

    ngOnInit(): any {
    this.fetchProducts();
    }

}
import {Component, Input, Output, EventEmitter, OnInit} from 'angular2/core';
import {StoreProduct} from './storeproduct.service';

@Component({
    selector: 'category-selector',
    template: `
        <form class="ui form">
            <select #sel (change)="selection.emit(sel.value)" class="ui fluid dropdown">
                <option value="" selected>{{defaultText}}</option>
                <option *ngFor="#category of categories" value="{{category}}">{{category}}</option>
            </select>
        </form>
    `,
    providers: [StoreProduct]
})
export class CategorySelector implements OnInit {

    @Output() selection = new EventEmitter();
    @Input() defaultText: string = 'No category selected';

    categories: string[];

    constructor(private sp: StoreProduct) {}

    ngOnInit(): any {

        let source = this.sp.fetchCategories();
        let sub = source.toPromise().then((val: string[]) => {
            this.categories = val;
        });
    }

}
import{Component,Input,Output,EventEmitter,OnInit}来自'angular2/core';
从“./StoreProduct.service”导入{StoreProduct};
@组成部分({
选择器:“类别选择器”,
模板:`
{{defaultText}}
{{category}}
`,
提供者:[存储产品]
})
导出类CategorySelector实现OnInit{
@Output()selection=neweventemitter();
@Input()defaultText:string='未选择任何类别';
类别:字符串[];
构造函数(私有sp:StoreProduct){}
ngOnInit():任何{
让source=this.sp.fetchCategories();
让sub=source.toPromise()。然后((val:string[])=>{
this.categories=val;
});
}
}

由于组件A和组件B是兄弟,并且您希望A通知B,因此您有两种选择:

  • 将事件/值从A向上发送到父级,然后数据绑定到B上的输入属性。如果需要在值更改时在B中运行某些逻辑,请实现lifecycle hook
    ngOnChanges()
    (注释中已经提到@rrhohnson85)。我不建议在setter内部触发此逻辑
  • 将共享服务(@rrhohnson85在评论中也提到过)与主题或可观察对象一起使用。组件A将调用服务上的一个方法,该方法调用主题或可观察对象上的
    next()
    。组件B将
    subscribe()
    订阅受试者或可观察者,以获得变更/事件的通知
    有关使用主题的示例,请参见
    查看这个SO问题,例如,使用可观察对象的示例

您可以尝试在ProductSelector上实现ngOnChanges lifecycle钩子,并在其类别输入属性发生更改时运行
fetchProducts
——我认为这会起作用。@rrjohnson我刚刚发现了这一点!这一周都在哪里?!哈哈哈,我只是在一周前做类似的事情时偶然发现的。我需要更深入地探索钩子,我相信它们迟早会派上用场。@rrjohnson 85你知道有没有一种真正的方法可以将事件从A发送到B,而不仅仅是倾听变化?我不确定,但我怀疑你可以通过服务来实现这一点,因此这将是一个从a到B的工作流,而不仅仅是从a到B的工作流。如果有其他方法,我还没有找到它,但是如果你找到了,请告诉我。