Reputation: 2549
I am trying to figure out cross component communication in Angular 2 and failing right now. Basically I have 3 components: a AddProduct component which in this case is the parent, a CategorySelector component which uses a service to populate a dropdown with a list of categories, and a ProductSelector component which takes a category as a parameter and populates a dropdown with a list of Products that belong to the selected category.
What I am trying to figure out is how to make it so that when the CategorySelector changes the ProductSelector runs the function necessary to get the new list of products.
Here is my code:
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>
add-product.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() {
}
}
product-selector.component.ts
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();
}
}
category-selector.component.ts
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;
});
}
}
Upvotes: 1
Views: 1779
Reputation: 364747
Since component A and component B are siblings, and you want A to notify B, you have two choices:
ngOnChanges()
(as @rrhohnson85 already mentioned in a comment). I don't recommend triggering this logic inside of a setter.next()
on the Subject or Observable. Component B will subscribe()
to the Subject or Observable to be notified of changes/events. Upvotes: 2