问题
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?
回答1:
There are a couple of strategies to solve this. Overall, this is a state management problem: Multiple components are working on one joint state.
Option 1: Parent Component Manages State
This might be the most simple solution.
- The parent component that holds all other components has a list of selected products.
- The child components that let the user pick a product have an @Output() EventEmitter that emits when the user picks a product. The parent component listens to that output and adds the emitted product to its list of products.
- The child components that display selected products have an @Input() array of products, based on which they display products. The parent component sets this input to its product list.
Option 2: State Service
Quickly implemented, but much cleaner separation of concerns than #1.
- Implement an @Injectable
StateService
. It has a) aBehaviorSubject<Product[]>
with a list of products, b) a methodaddProduct(product: Product)
that adds a product to the current value of theBehaviorSubject
and emits it. - Each component uses that service (
constructor(stateService: StateService)
). When the user picks a product, the component callsthis.stateService.addProduct(product)
. - Components that display products listen to changes in the service's product list:
this.stateService.products.subscribe(products => this.products = products)
and display the products accordingly.
Option 3: Use a State Store Library
Use something like NGRX or Redux that takes care of state management for you.
回答2:
you can add a productsSelected array to your ProductsComponent, into which you push selected products when selected and then pass it as an Input to your ReceiptItemComponent ( or ReceiptItemsComponent ). Don't forget of [()] -- box of bananas, two way data binding - if you are going to change the quantity in the child component but you are going to save the array in your parent component.
You could use a service also, that holds the selectedProducts as a behaviorSubject and inject it in both components. Then you have to subscribe to changes in both components to receive the updates.
回答3:
This is exactly what I wrote my library RxCache for. It gives push data flow to Angular applications without having to add the complexity and ridiculous amount of boiler plate code involved in adding a store like NGRX.
https://github.com/adriandavidbrand/ngx-rxcache
Testbed on StackBlitz - https://stackblitz.com/edit/angular-3yqpfe
A redo of the official ngrx example app can be seen here on StackBlitz - https://stackblitz.com/edit/github-tsrf1f
来源:https://stackoverflow.com/questions/51079474/what-is-a-better-way-and-how-to-achieve-sending-object-from-one-nested-component