how to refresh the page after delete in angular5

34,288

Solution 1

Cause

Your table isn't being updated because the model ( data ) wasn't updated after the API call. There are a few ways to update the model, and I recommend either Options 3 or 2 in this answer.

Option 1

As some have already stated, the first way is to remove the element from the array in the view-model:

delFunc(id){
    this.add.deleteProd(id);
    this.data = this.data.filter(item => item.id != id);
}

The drawback to this approach is that even though the item has been removed in the frontend, how can you be sure that it has indeed been successfully removed from the database in the backend? Meaning, the item would be removed from your frontend HTML table even if this.add.deleteProd(id) isn't working properly and the object wasn't actually deleted in the backend. Hence you can't be sure if the frontend View accurately represents the reality of the backend.

Option 2

The second way is to "reload" the table by querying the backend again. This takes the "least work" as all you have to do is simply call the function to load the data again:

delFunc(id) {
    this.add.deleteProd(id)
    .subscribe(()=> {
        this.fetchData();
    });
}

ngOnInit() {
    this.fetchData();
}

fetchData() {
    this.allService.getAlldata().subscribe(data =>{
        this.data = data;
    });
}

Here, you gain "accuracy" of reality but sacrifice performance as you are making two REST calls each time you delete.

Option 3

The third way takes the "most work", but provides a compromise between accuracy of reality and performance. Basically you will need to re-write the backend such that after doing the database deletion, the backend REST/API method returns the new set of data that is now in the database.

Then, you can do something like this in your Angular component:

delFunc(id) {
    this.add.deleteProd(id)
    .subscribe(newData => {
        this.data = newData;
    });
}

This assumes that you have control over the backend code. You might need to do this.data = newData.json(); instead, depending on what the this.add.deleteProd(id) method returns.

Pick the option that best suits your situation. Let me know if this works for you.

Solution 2

You don't need to navigate, you should remove the deleted product from your data that is used to create your template.

  delFunc(id){
    // console.log("Delete ",id);
    this.add.deleteProd(id);
    const item = this.data.find(item => item.id === id);
    this.data.splice(this.data.indexOf(item)));
  }

You could of course just trigger your data to reload and again call your back-end, which would be suboptimal.

Solution 3

No need to reload the page , just pass the index from template side and remove that data from index on delete success.

Template Side

<tr *ngFor="let prod of data;let i = index">
    ....
    <input type="button" class="btn btn-danger" (click) = "delFunc(prod._id,i)" class="del-btn"  value="Delete">
    ....
</tr>

Component Side :

delFunc(id , index){
    // console.log("Delete ",id);
    this.add.deleteProd(id).subscribe(()=>{
        this.data.splice(index, 1);
    });
}

Solution 4

You can create a method to get all Data as:

getAllData() {
  this.allService.getAlldata().subscribe(data => {
    this.data = data;
  })
}  

This method can be used as a callback method in your Delete function.
Something like this:

delFunc(id) {
  this.add.deleteProd(id).subscribe(() => this.getAllData());
}

This way the data will be refreshed every time, a delete happens.

Solution 5

Change your click event to pass in the whole object:

<input type="button" class="btn btn-danger" routerLink="/reload" (click) = "delFunc(prod)" class="del-btn"  value="Delete">

And your delFunc like:

delFunc(prod){
    this.data.splice(this.data.indexOf(prod), 1);
    this.add.deleteProd(prod._id);
}
Share:
34,288
Coder
Author by

Coder

Updated on July 09, 2022

Comments

  • Coder
    Coder almost 2 years

    I was making a mean-stack shopping app(Angular 5). I have made a manage product component with a list of all the products and a delete button. Delete button works but the product is listed in table till now as it was deleted from database. So, I was wondering is there any possible way to re-render or refresh the component after deleting. I tried to navigate to same page but it won't work as angular does not allow that. Please can anyone help. I could not find any specific answer to my query on stackoverflow so I had to ask It.

    My manage-product.component.ts is :-

    import { Component, OnInit } from '@angular/core';
    import { ProductManageService, ProductDetails } from '../product-manage.service';
    import { AllService } from '../all.service';
    import { HttpClientModule, HttpClient } from '@angular/common/http';
    import { Router } from '@angular/router';
    import { Location } from '@angular/common';
    
    @Component({
      selector: 'app-manage-product',
      templateUrl: './manage-product.component.html',
      styleUrls: ['./manage-product.component.css']
    })
    export class ManageProductComponent implements OnInit{
    
        prodData : ProductDetails = {
        prodName: '',
        prodPrice: '',
        prodImage: '',
        prodSize: ''
        }
    
        data: any=[];
    
      constructor(private add:ProductManageService,
        private router: Router,
        private http:HttpClient,
        private allService :AllService,
        private location : Location) { }
    
      addProduct(){
        this.add.addProduct(this.prodData).subscribe(()=>{
            console.log("SENT",this.prodData);
        },(err)=>{
            console.log("Error",err);
        })
      }
    
      delFunc(id){
        // console.log("Delete ",id);
        this.add.deleteProd(id);
        this.router.navigateByUrl("/reload");
      }
    
      ngOnInit() {
    
        this.allService.getAlldata().subscribe(data =>{
          console.log("data",data);
          this.data = data;
        });
    
        console.log(this.data);
    
    
    }
    
    }
    

    My html file for manage component is:-

        <div class="container">
    
        <form (submit)="addProduct()">
          <div class="form-group">
            <label for="name">Product Name</label>
            <input name="prodName" type="text" class="form-control" id="name" placeholder="Tshirt" [(ngModel)]="prodData.prodName">
          </div>
          <div class="form-group">
            <label for="price">Price</label>
            <input name="prodPrice" type="text" class="form-control" id="price" placeholder="1.1" [(ngModel)]="prodData.prodPrice">
          </div>
          <div class="form-group">
            <label for="image">Price</label>
            <input name="prodImage" type="text" class="form-control" id="image" placeholder="Link to image" [(ngModel)]="prodData.prodImage">
          </div>
          <div class="form-group">
            <label for="size">Price</label>
            <input name="prodSize" type="text" class="form-control" id="size" placeholder="M" [(ngModel)]="prodData.prodSize">
          </div>
          <button type="submit" class="btn btn-default">Submit</button>
        </form>
    
        <table class="table table-hover">
            <tr>
                <th>Product Name</th>
                <th>Product Price</th>
                <th>Product Size</th>
                <th> </th>
            </tr>
                <tr *ngFor="let prod of data">
                    <td>{{ prod.prodName }}</td>
                    <td>{{ prod.prodPrice }}</td>
                    <td>{{ prod.prodSize }}</td>
                    <td>
                        <input type="button" class="btn btn-danger" routerLink="/reload" (click) = "delFunc(prod._id)" class="del-btn"  value="Delete">
                    </td>
                </tr>
        </table>
    
    </div>
    

    app.module.ts in case of you need:-

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { HttpClientModule } from '@angular/common/http';
    import { HttpModule } from '@angular/http';
    import { FormsModule } from '@angular/forms';
    import { RouterModule, Routes } from '@angular/router';
    
    import { AllService } from './all.service';
    import {AuthGuardService} from './auth-guard.service';
    import {AuthenticationService} from './authentication.service';
    import { ProductManageService } from './product-manage.service';
    
    import { AppComponent } from './app.component';
    import { FrontComponent } from './front/front.component';
    import { ContentComponent } from './content/content.component';
    import { ProductDetailComponent } from './product-detail/product-detail.component';
    import { RegisterComponent } from './register/register.component';
    import { LoginComponent } from './login/login.component';
    import { ProfileComponent } from './profile/profile.component';
    import { ManageProductComponent } from './manage-product/manage-product.component';
    
    const routes = [
      {
        path: '',
        component: ContentComponent
      },
      {
        path: 'product',
        component: ProductDetailComponent
      },
      { 
        path: 'login',
         component: LoginComponent 
      },
      {
       path: 'register',
        component: RegisterComponent
      },
      {
       path: 'profile',
       component: ProfileComponent,
       canActivate: [AuthGuardService] 
      },
      {
        path: 'manage',
        component: ManageProductComponent,
      },
      { path: 'reload',
        redirectTo: 'manage',
        pathMatch: 'full'
      },
    ];
    
    @NgModule({
      declarations: [
        AppComponent,
        FrontComponent,
        ContentComponent,
        ProductDetailComponent,
        RegisterComponent,
        LoginComponent,
        ProfileComponent,
        ManageProductComponent
      ],
      imports: [
    
        BrowserModule,
        FormsModule,
        HttpClientModule,
        HttpModule,
        RouterModule.forRoot(routes, {
          onSameUrlNavigation: 'reload'
        }),
      ],
      providers: [
        AllService,
        AuthenticationService, 
        AuthGuardService,
        ProductManageService
      ],
      bootstrap: [AppComponent],
      exports: [RouterModule]
    })
    export class AppModule { }
    
  • Jan Wendland
    Jan Wendland about 6 years
    You may want to store the spliced object and undo the splice by readding the element to the local array in case the serverside delete operation fails though.
  • nixxx
    nixxx over 4 years
    Why not call the splice operation after the record successfully deletes? In that case you could listen in an async operation, then when results are back and its successful, you can then splice/ remove record from frontend.
  • Jan Wendland
    Jan Wendland over 4 years
    Because it feels more responsive when the entry disappears right away.