Reputation: 42957
I am not so into Angular and TypeScript (I came from Java) and I have the following problem to solve. I don't know if the solution that I think to use is correct or if there are bettere solutions.
Basically I have a component named order-manager.component that is a parent component rendering this tables:
This parent component contains the list of object representing a single row:
orders: any[];
and into the ngOnInit() retrieve the list using a service.
As you can see in the previous printscreen each rows of my table can be expanded in order to show\edit the details of the specific object.
So to do this I used a sub component named order-details. So basically in my parent component HTML I have something like this:
DETTAGLIO ORDINEThis order-details subcomponent have 2 subcomponents itself: one for the view mode and the second one for the edit mode (hightlited in the previous screenshot).
So basically into my code of this order-details component I simply have:
<p-selectButton [options]="editOrderOption"
[(ngModel)]="editOrderSelectedOption"
(onChange)="editOrderOptionOnChange($event, orderDetail.id)"></p-selectButton>
<div *ngIf="editOrderSelectedOption=='view';then view_content else edit_content">here is ignored</div>
<ng-template #view_content>
<app-view-order [orderDetail]="orderDetail"></app-view-order>
</ng-template>
<ng-template #edit_content>
<app-update-order [orderDetail]="orderDetail"></app-update-order>
</ng-template>
Basically the user choose the view or edit mode by the select button and a sub component is rendered in the page.
In the specific case we are into edit mode using this update-order component.
As you can see in the previous image this update-order component allow the user to edit the form and at the end it contains the Delete button. Clicking this button I want to delete the object representing this order (this row of the table) from my table.
And here my problem. The list of object representing the table rows is defined in the first order-manager.component parent component and the button is defined into the second level update-order sub component, this is the hierarchy:
order-manager component
|
|
|---------> order-details component
|
|
|----------------> update-order component
To solve this problem I was thinking that I can do something like this:
The user click on the Delete button defined into update-order sub component. This is handled by a method that emit an event containing the ID of the current row (it is the unique value of the object field.
Into the order-manager parent component I listen for this event. When the event is received it is removed from the orders list representing the list of rows of my table.
Do you think that it is a pretty decent and neat solution to achieve this task or am I missing something and there are better solutions?
Upvotes: 1
Views: 860
Reputation: 11
Instead, you can create a data service which updates and fetch the data through it
import { Injectable } from '@angular/core';
import { Subject, Observable } from 'rxjs';
@Injectable()
export class MessageService {
private siblingMsg = new Subject<string>();
constructor() { }
/*
* @return {Observable<string>} : siblingMsg
*/
public getMessage(): Observable<string> {
return this.siblingMsg.asObservable();
}
/*
* @param {string} message : siblingMsg
*/
public updateMessage(message: string): void {
this.siblingMsg.next(message);
}
}
and from the component, you can set the value using subscribe
import { Component, OnInit, OnDestroy } from '@angular/core';
import { MessageService } from './message.service';
...
export class AppComponent implements OnInit{
public messageForSibling: string;
public subscription: Subscription;
constructor(
private msgservice: MessageService // inject service
) {}
public ngOnDestroy(): void {
this.subscription.unsubscribe(); // onDestroy cancels the subscribe request
}
public ngOnInit(): void {
// set subscribe to message service
this.subscription = this.messageService.getMessage().subscribe(msg => this.messageForSibling = msg);
}
}
Upvotes: 1
Reputation: 156
At first, you should create an output property in your child component.
@Output()
updated = new EventEmitter<boolean>();
saveButtonClicked() {
//do update
this.updated.emit(true); //update success
}
Define it in your html:
<ng-template #edit_content>
<app-update-order [orderDetail]="orderDetail" (updated)="orderUpdated($event)"></app-update-order>
</ng-template>
Now, you can listen update events in parent component.
orderUpdated(updated:boolean){
if(updated){
}
}
You can find more information about component interaction here
Upvotes: 0
Reputation: 15083
Emitting a value will work.
A simpler solution will be to create a service that may track user actions.
Create a Service say OrderChangeService
and inject this on both order-manager component
and update-order component
export class OrderChangeService {
deleteIdSubject$ = new Subject<number>(); // import { Subject } from rxjs
deleteIdAction$ = deleteIdSubject$.asObservable()
}
Now in update-order component
when a user clicks to delete a specific order, you call the next() function on the subject
deleteOrder(id: number) {
deleteIdSubject$.next(id);
}
In your order manager component you can now subscribe to deleteIdAction$
in your ngOnInit()
function
deleteIdAction$ = this.orderChangeService.deleteIdAction$ // make sure you inject service in the constructor
ngOnInit() {
this.deleteIdAction$.subscribe({
next: (id) => {
// Do Delete action for item with id
}
})
}
The basic idea is that a service can be used to pass information from one component to another. Emitting values may be problematic as the depth of nested components increases
The Best approach would actually be to use NgRx
for state management. May be a bit difficult to use but produces better result. You may have a look at the official documentation of NgRx
Upvotes: 2