0

I am using angular6, and for showing some records i am using angular material data table.

When i save or delete any customer, the changes are persisting in DB but not reflecting in the UI, i need to do page refresh for reflecting the changes.

I have given the code on below, first it will load customerList then customer component as a popup

I am doing Rest Call for CRUD operations.

customerList.component.ts
**************************

import { Component, OnInit } from '@angular/core';
import { UserService } from '../services/user.service';
import { MatTableDataSource,MatDialog,MatDialogConfig } from '@angular/material';
import { CustomerComponent } from '../customer/customer.component';

@Component({
  selector: 'customer-list',
  templateUrl: './customer-list.component.html',
  styleUrls: ['./customer-list.component.css']
})
export class CustomerListComponent implements OnInit {

  dataSource;
  searchKey:string;

  displayedColumns = ['name','actions'];

  constructor(private service : UserService,
              private dialog : MatDialog) { }

  ngOnInit() {
    this.fetchCustomer();
  }

  onSearchClear(){
    this.searchKey="";
    this.applyFilter();
  }

  applyFilter(){
    this.dataSource.filter = this.searchKey.trim().toLowerCase();
  }

  newCustomer(){
    this.service.initializeForm();
    const dialogConfig = new MatDialogConfig();
    //dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = "60%";
    this.dialog.open(CustomerComponent, dialogConfig).afterClosed().subscribe(() => this.fetchCustomer());
  }


  viewCustomer(customer){
    console.log(event.target);
    this.service.populateForm(customer);
    const dialogConfig = new MatDialogConfig();
    //dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = "60%";
    this.dialog.open(CustomerComponent,dialogConfig);
  }

  editCustomer(customer){
    this.service.populateForm(customer);
    console.log(customer);
    const dialogConfig = new MatDialogConfig();
    //dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = "60%";
    this.dialog.open(CustomerComponent,dialogConfig);
  }


    deleteCustomer(id){
    this.service.deleteCustomerData(id).subscribe(
      data => console.log("success", data),
      error => console.error("Error!",error)
    );
    this.populateTable();
  }

  fetchCustomer(){
    this.service.getUser().subscribe( results => {
      if(!results){

        return;
      }
      console.log(results);
      this.dataSource = new MatTableDataSource(results);
  })
  }
}

customerList.component.html
*******************************

<h1>Customer-List</h1>
<div class="search-div">
    <button mat-raised-button (click)="newCustomer()" style="position: absolute; right: 0;">
      <mat-icon>add</mat-icon>New Customer
    </button>
  </div>

  <div>
    <mat-table [dataSource]="dataSource">
      <ng-container matColumnDef="name">
        <mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
        <mat-cell *matCellDef="let user"><a href>{{user.name}}</a></mat-cell>
      </ng-container>
      <ng-container matColumnDef="actions">
        <mat-header-cell *matHeaderCellDef>Actions </mat-header-cell>
        <mat-cell *matCellDef="let row">
          <button mat-icon-button matTooltip="Click to View" (click)="viewCustomer(row)" class="iconbutton" color="primary">
                <mat-icon>visibility</mat-icon>
              </button>
          <button mat-icon-button matTooltip="Click to Edit" (click)="editCustomer(row)" class="iconbutton" color="primary">
              <mat-icon>edit</mat-icon>
            </button>
          <button mat-icon-button matTooltip="Click to Delete" (click)="deleteCustomer(row)" class="iconbutton" color="warn">
              <mat-icon>delete</mat-icon>
            </button>
        </mat-cell>
      </ng-container>

      <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
      <mat-row *matRowDef="let row; columns:displayedColumns"></mat-row>
    </mat-table>
  </div>


customer.component.ts
**********************
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl,FormBuilder,Validators } from '@angular/forms';
import { MatDialogRef } from '@angular/material';
import { UserService } from '../services/user.service';

@Component({
  selector: 'app-customer',
  templateUrl: './customer.component.html',
  styleUrls: ['./customer.component.css']
})
export class CustomerComponent implements OnInit {

  constructor(private customerService : UserService,
              public dialogRef : MatDialogRef<CustomerComponent>) { }

  ngOnInit() {
    this.customerService.getUser();
  }

  onSubmit(){
    this.customerService.customerData(this.customerService.cutsomerForm.value).subscribe(
      data => console.log("success", data),
      error => console.error("Error!",error)
    );
   this.onClose();
  }

  onClose(){
    this.clearForm();
    this.dialogRef.close();
  }

  clearForm(){
    this.customerService.cutsomerForm.reset();
    //this.customerService.initializeForm();
  }
}

customer.component.html
*************************

<div class="container-fluid">
    <h2>New Customer</h2>
    <form [formGroup]="customerService.cutsomerForm" (ngSubmit)="onSubmit()" #newCustomer="ngForm">
      <div class="form-group">
        <label>Customer Name</label>
        <input [class.is-invalid]="customerService.cutsomerForm.get('name').invalid &&
                                   customerService.cutsomerForm.get('name').touched" formControlName = "name" type="text" class="form-control">
      </div>
      <input type="hidden" formControlName="id"> 

      <div class="form-group">
        <label>userName</label>
        <input formControlName = "username" type="text" class="form-control">
      </div>

      <div class="form-group">
        <label>email</label>
        <input formControlName = "email" type="text" class="form-control">
      </div>

      <div class="form-group">
        <label>phone</label>
        <input formControlName = "phone" type="text" class="form-control">
      </div>

      <div>
        <button class="btn btn-primary" [disabled] = !newCustomer.valid type="submit">Submit</button>
      </div>

    </form>
    <button class="btn btn-danger" (click)="clearForm()">Clear</button>
  </div>

user.service.ts


import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Customer } from '../models/Customer.model';
import { FormGroup, FormControl,FormBuilder,Validators } from '@angular/forms';

@Injectable({
  providedIn: 'root'
})
export class UserService {

 private serviceUrl = "https://jsonplaceholder.typicode.com/users";

  // private findAllCustomers = "http://localhost:8080/findAllCustomers";

  // private insertNewCustomer = "http://localhost:8080/addCustomer";

  constructor(private http : HttpClient,
    private fb : FormBuilder) { }

  cutsomerForm = this.fb.group({
    id : [''],
    name : ['',Validators.required],
    username : [''],
    email : [''],
    phone : ['']
  })

  initializeForm(){
    this.cutsomerForm.setValue({
      id : '',
      name : '',
      username : '',
      email : '',
      phone : ''
    });
  }

  getUser() : Observable<Customer[]> {
      return this.http.get<Customer[]>(this.serviceUrl);
  }

  customerData(customer: Customer): Observable<Customer> {
    return this.http.post<Customer>(this.serviceUrl,customer);
  }

  populateForm(customer){
    this.cutsomerForm.setValue(customer);
  }
}
mohan
  • 447
  • 4
  • 11
  • 26

2 Answers2

3

You are saving or deleting a customer from the table, but the dataSource is using the data that you have already fetched from the database. It cannot get the updated data unless you manually do it.

While saving a new customer, you'll have to make the getUser() request again ( or push the customer object in the results variable) and initialize the dataSource again.

While deleting, again, either make the call again, or iterate through the result variable, find the customer that was deleted, remove it from the array, and reinitialize the dataSource.

Akash Srivastav
  • 756
  • 5
  • 15
  • thats correct, thanks for your answer. The home page is CustomerList component, from there i am opening a dialog box and there i am doing the adding, deleting each customer, that each Customer Component. I hope i am clear with the explanation. "this.dialog.open(CustomerComponent,dialogConfig);" So once i will submit customer component, i need to call customerList component by passing the object or what? – mohan Jun 14 '19 at 09:11
  • @mohan if you're routing somewhere else after submitting, then there's no issue, the component will automatically make the request because of the function call in `ngOnInit()`. If you're staying on the same screen, just make a call to the `getUser()` function after the save (or delete) request is completed. – Akash Srivastav Jun 14 '19 at 09:23
  • customerList Compoenent is the parent one and in this compoenent i am displaying all the records. After clicking on the new Customer button which is present on this page i am opening a dialog box which is Customer Component and in this component i am saving new Customer and closing the dialogBox, thats why issue is coming, i am not able to link this dialogBox and the parent component. – mohan Jun 14 '19 at 09:55
  • the below method is from the dialogComponent. Like this i am submitting the page and closing the dialog. onSubmit(){this.customerService.insertCustomerData(this.customerService.cutsomerForm.value).subscribe( data => console.log("success", data), error => console.error("Error!",error) ); this.customerService.getUser().subscribe( results => { console.log(results); }); this.onClose(); } – mohan Jun 14 '19 at 09:55
  • Can you create a stackblitz so it's easier to understand? Although, wrap the whole service call to getUser `this.service.getUser().subscribe(..)`in the `ngOnInit()` into a separate function (say, `getUsers()`), and then call that function in `ngOnInit()`, and after receving the success response from the save or delete request. Some thing like this, `data => { console.log('success', data); this.getUsers(); }, error => ... this.onClose();` – Akash Srivastav Jun 14 '19 at 10:09
  • Hi @Akash, i had edited my question with sample code, did you find anything? – mohan Jun 18 '19 at 04:02
  • @mohan Hi, Mohan, it's almost right. The only change that I think you need to make is that you need to wait for the add or delete calls to finish before calling `this.onClose()`, which is invoking the `fetchUsers()` function. Either 1: Put the `this.onClose()` inside the response of the http call, or 2: when the call is finished, i.e after `data => console.log("success", data), error => console.error("Error!",error)` call `fetchUsers()` again. – Akash Srivastav Jun 18 '19 at 04:14
  • if i want to show some message of operation...like delete operation is successful or something after button clicked, which component will be good? – mohan Jun 18 '19 at 05:36
  • @mohan If you don't want to put much work into it, you can just use a variable for success or failure message and show it under the form after the corresponding condition of success or failure. However, I like to use a pop-up dialog to show the success or failure message. I have to create that component just once, and I can use it anywhere in my angular app to show success/error messages (or to take user input). – Akash Srivastav Jun 18 '19 at 07:54
2

Akash's approach is correct. In addition to his approach you should use afterClosed() method to link MatDialog to current component and get notified when the dialog is closed. After the dialog is closed, just fetch users again.

  ngOnInit() {
    this.fetchUsers();
  }

  newCustomer(type) {
    this.service.initializeForm();
    const dialogConfig = new MatDialogConfig();
    //dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = "60%";
    dialogConfig.id = type;
    this.dialog.open(CustomerComponent, dialogConfig).afterClosed().subscribe(() => this.fetchUsers());
  }

  fetchUsers() {
    this.service.getUser().subscribe(results => {
      if (!results) {
        return;
      }
      console.log(results);
      this.dataSource = new MatTableDataSource(results);
      this.dataSource.sort = this.sort;
      this.dataSource.paginator = this.paginator;
    })
  }

Also if you share the code for deletion and CustomerComponent it would be easier to analyse any potential problems.

ysf
  • 4,634
  • 3
  • 27
  • 29