I'm working on simple application about products, basically when user choose a product it should be sent to another component which would hold product.
Product is allways choosen one by one, I am NEVER sending a LIST! Only item by item!
So basically when I click on any of products in the middle of screen (Product food 1, Product food 2, Product food 3) it should be sent to the right part of the screen which is also separated component.
So my middle component looks like this:
<div *ngFor="let product of products;" class="product-holder">
<div id="product.id" class="product" [style.background]="'url('+ product.imgUrl +')'">
<p class="product-price">{{product.mpc | number}}</p>
<p class="product-title">{{product.title}}</p>
</div>
</div>
And a typescript code:
@Component({
selector: 'app-products',
templateUrl: './app-products.component.html',
styleUrls: ['./app-products.component.css']
})
export class ProductsComponent implements OnInit {
products: Article[];
constructor(private _sharedService: SharedService) { }
ngOnInit() {
this._sharedService.getEventSubject().subscribe((param: any) => {
if (param !== undefined) {
this.theTargetMethod(param);
}
});
}
theTargetMethod(param) {
// Here I am populating middle screen with products
this.products = param;
}
}
And now I will post my right component which should receive product :
<div class="order-article">
<div class="order-img"></div>
<div class="order-title">
<p>HERE I SHOULD WRITE ARTILE TITLE</p>
</div>
<div class="order-quantity pull-right">
<span class="order-quantity-number">ARTICLE QUANTITY</span>
</div>
</div>
export class ReceiptItemComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
So this 'right' component should receive clicked product from the middle, and I don't know how to do it, I red about @Input
and @Output
decorators and also about services
, I guess @input and @output are right solution here because I'm sending one by one item?
But I don't know practically how to to solve this..
Any kind of help would be awesome
Thanks
AFTER fjc help:
<div *ngFor="let product of products;" class="product-holder" (click)="addReceiptItem(article)">
<div id="product.id" class="product" [style.background]="'url('+ product.imgUrl +')'">
<p class="product-price">{{product.mpc | number}}</p>
<p class="product-title">{{product.title}}</p>
</div>
</div>
As you can see guys:
1.) I added addReceiptItem
method
2.) This method accepts clicked product:
addReceiptItem(receiptItem: Product) {
this._sharedService.addReceiptItem(receiptItem);
}
3.)Injected service '_sharedService
' and created method there called also 'addReceiptItem'
4.)In my service I created BehaviorSubject
like this: private receiptItem = new BehaviorSubject<any>(undefined);
4.)Method in a service looks like this:
addReceiptItem(receiptItems: Product) {
this.arr1.push(receiptItems);
this.receiptItem.next(this.arr1);
}
This method is pushing clicked items to an array which will be send to a component that displays products
4.11) Added also method for getting data which returns BehaviorSubject:
getReceiptItem(): BehaviorSubject<any> {
return this.receiptItem;
}
5.)Edited Components that display products (code was posted also before doing anything - empty typescript file), and now it looks like this:
export class ReceiptItemComponent implements OnInit {
constructor(private _sharedService: SharedService) { }
receiptItems: Product[];
ngOnInit() {
this._sharedService.getReceiptItem().subscribe(products => this.receiptItems = products);
}
}
Left is only to do destroy somehow?
There are a couple of strategies to solve this. Overall, this is a state management problem: Multiple components are working on one joint state.
This might be the most simple solution.
Quickly implemented, but much cleaner separation of concerns than #1.
StateService
. It has a) a BehaviorSubject<Product[]>
with a list of products, b) a method addProduct(product: Product)
that adds a product to the current value of the BehaviorSubject
and emits it.constructor(stateService: StateService)
). When the user picks a product, the component calls this.stateService.addProduct(product)
. this.stateService.products.subscribe(products => this.products = products)
and display the products accordingly.Use something like NGRX or Redux that takes care of state management for you.