user94614
user94614

Reputation: 511

Angular - Refresh/Get data after delete

I've landed on a project in flight using Angular without knowing too much about Angular. I'm currently working on a simple CRUD screen. After deleting a row, how can I then "refresh" the UI? Here are the methods inside my component:

    AATList:IAat[];

confirmDelete(): void{
    //this.myService.deleteAAT(this.satNumber).subscribe(data => {this.AATList = data;});
    //this.myService.deleteAAT(this.satNumber).subscribe(() => {this.getAATtEntries(); });
    this.myService.deleteAAT(this.satNumber).subscribe();
    this.getAatEntries();
    this.modalRef.hide();
}

getAATtEntries() {
    console.log("entries");
    this.myService.getAATList().subscribe(data => {this.AATList = data});
}

(Added on edit, inside component):

openDeleteModal(template: TemplateRef<any>, satNumber: number) {
    this.satNumber = satNumber;
    this.modalRef = this.modalService.show(template, {class: 'modal-sm'});
  }

Services:

getAATList() {
    return this.httpClient.get<ISmt[]>(environment.ApiEndPoint + '/api/SMTDatas', {withCredentials:true});
}

deleteAAT(satNumber : number) {
    return this.httpClient.delete(environment.ApiEndPoint + '/api/SMTDatas/' + satNumber, {withCredentials:true} )
}

(I am using the HttpClient from @angular/common/http for the services)

I've tried the first three lines in the confirmDelete method without avail. What am I missing here? My grasp of Angular is not good so feel free to point out anything else.

UPDATE: HTML:

    <a class="text-danger" data-toggle="tooltip" data-placement="top" title="Delete" (click)="openDeleteModal(deleteTemplate, smt.SMTNumber)"><i class="fa fa-trash"></i>Delete</a>
...
    <ng-template #deleteTemplate>
      <div class="modal-body text-center">
        <p>Are you sure you want to delete this SAT?</p>
        <button type="button" class="btn btn-default" (click)="confirmDelete()" >Yes</button>
        <button type="button" class="btn btn-primary" (click)="denyDelete()" >No</button>
      </div>
    </ng-template>

Upvotes: 3

Views: 13438

Answers (3)

saglamcem
saglamcem

Reputation: 687

Note: Out of feeling responsible, I've added an updated information below the post to give slightly "better" insight


TL;DR: Read about Subscriptions and Subjects, and on how to establish communication between a component and a service. You can achieve what you want by either making a GET request after making a successful DELETE request, or updating your UI by locally removing the item from your list after making a successful DELETE request.

Longer version:

An idea could go as follows:

If you make a change that you'll want to be able to see later on (like 99,9% of the apps) you'll want to make a backend call.

How you update your UI kind of depends on how you'd like to proceed with it, after you've made the backend call.

So consider a case where you delete an item from the list. You send a delete request for that particular item, and receive a response from the backend. This response should tell you whether the delete operation you made was successful or not.

Based on this information, you can

1) find the item in the list by iterating through it and delete it locally (quicker)

2) make another GET request to the backend and display the newly updated result after your successful deletion (safer, but you end up making 2 requests for each operation).

How you could approach the "is deletion successful" question depends on your implementation, but I'll share one below.

For this, it would be helpful for you to read about Subscriptions and Subjects using rxjs. I'll be writing by following the 2nd option I mentioned above.

On the service where you're making the call, you can create a Subject. You will use this subject to notify the listeners (meaning whoever's subscribed to this event) about any updates by using the next method.

In your service, you can create a new Subject as follows:

private _deleteOperationSuccessfulEvent$: Subject<boolean> = new Subject();

and create a getter for it as follows:

get deleteOperationSuccessfulEvent$(): Observable<boolean> {
    return this._deleteOperationSuccessfulEvent$.asObservable();
} 

When you receive a response for your HTTP DELETE request, based on success or failure, you can emit a true or false value as follows:

this._deleteOperationSuccessfulEvent$.next(true);

So far we're emitting the information that the delete operation was successful, or not.

But nobody's listening to it yet. So in your component, you can create a subscription:

deleteOperationSuccessfulSubscription: Subscription;

and in your ngOnInit method, you can subscribe to the deleteOperationSuccessfulEvent$ created in your service:

this.deleteOperationSuccessfulSubscription = this.yourService.deleteOperationSuccessfulEvent$.subscribe(...stuff will come here...);

(notice we used the deleteOperationSuccessfulEvent$ value, and not the private _deleteOperationSuccessfulEvent$.)

Now your component is listening to your service's delete.. event. We just need to act on it.

this.deleteOperationSuccessfulSubscription = this.yourService.deleteOperationSuccessfulEvent$
    .subscribe(isSuccessful => {
        if (isSuccessful === true) { 
            make a GET request and display the returning data, following similar steps to which we followed so far 
        } else {
            delete operation was NOT successful, you can display an error or retry etc.
        }
    });

Let me know if you have any questions.


Update: When doing all this, some things should be noted from an Angular & rxjs standpoint:

1- Try to not use .subscribe() in the typescript code - instead try to use the .pipe() operator to handle your logic. Instead, let Angular handle your subscription by using the async pipe in your template. You can add .catchError(err => ...) in your .pipe() to ensure that you catch your errors and handle them properly.

2- If you really have to use .subscribe(), don't forget to unsubscribe from that subscription in ngOnDestroy() {...}. Otherwise you're risking having memory leaks in your application.

ngOnDestroy() {
  this.mySubscription.unsubscribe();
} 

Upvotes: 6

ElasticCode
ElasticCode

Reputation: 7867

You can use onHidden event for the model (which fired when the modal has finished being hidden from the user) to get load your data as below.

constructor(private modalService: BsModalService) {
    this.modalService.onHidden.subscribe(() => {
         // Fired when the modal has finished being hidden from the user
        this.getAATtEntries();
    });
}

confirmDelete(): void{
    this.myService.deleteAAT(this.satNumber).subscribe(() => { this.modalRef.hide(); });
}

Upvotes: 0

AVJT82
AVJT82

Reputation: 73337

EDIT: I think that you are closing the modal, before the request has been executed. Also assumingly you would want to fetch the list in your parent, not in the modal. So first I would delete, hide the modal, listen to modal being closed in parent, and there re-fetch the list... so something like:

this.myService.deleteAAT(this.satNumber).subscribe(() => this.modalRef.hide());

Then in your parent, listen to the hide:

this.modalService.onHide.pipe(
  switchMap(() => this.myService.getAATList())
).subscribe(data => {this.AATList = data})

ORIGINAL:

When you do this:

this.myService.deleteAAT(this.satNumber).subscribe();
this.getAatEntries();

getAatEntries() is actually fired before the delete has finished (most likely), so you need to chain these requests, you can achieve this with switchMap:

this.myService.deleteAAT(this.satNumber).pipe(
  switchMap(() => this.myService.getAATList())
)
.subscribe((data: ISmt[]) => this.AATList = data);

Upvotes: 2

Related Questions