1

Can someone tell me the best way to update my mat-table (with a DataSource) when a row is edited? I'd like for the page to not have to refresh, thereby losing the currently selected row and any sorting.

My edit table is in a dialog box. Just don't know what to do when I get back to the table...

This is the table html:

    <mat-table id="mainTable" #table [dataSource]="dataSourceA" matSort>

      <ng-container matColumnDef="selection">
        <th mat-header-cell *matHeaderCellDef>
          <mat-checkbox (change)="$event ? masterToggle() : null" [checked]="selection.hasValue() && isAllSelected()"
            [indeterminate]="selection.hasValue() && !isAllSelected()">
          </mat-checkbox>
        </th>
        <td mat-cell *matCellDef="let row">
          <mat-checkbox (click)="$event.stopPropagation()" (change)="$event ? selection.toggle(row) : null"
            [checked]="selection.isSelected(row)">
          </mat-checkbox>
        </td>
      </ng-container>

      <ng-container matColumnDef="commonName">
        <mat-header-cell *matHeaderCellDef mat-sort-header>Common Name</mat-header-cell>
        <mat-cell *matCellDef="let certdata">{{certdata.commonName}}</mat-cell>
      </ng-container>

      <ng-container matColumnDef="owner">
        <mat-header-cell *matHeaderCellDef mat-sort-header>Owner</mat-header-cell>
        <mat-cell *matCellDef="let certdata">{{certdata.owner}}</mat-cell>
      </ng-container>

      <ng-container matColumnDef="expirationDate">
        <mat-header-cell *matHeaderCellDef mat-sort-header>Expiration Date</mat-header-cell>
        <mat-cell *matCellDef="let certdata">{{certdata.expirationDate | date}}</mat-cell>
      </ng-container>

      <ng-container matColumnDef="environment">
        <mat-header-cell *matHeaderCellDef mat-sort-header>Environment</mat-header-cell>
        <mat-cell *matCellDef="let certdata">{{certdata.environment}}</mat-cell>
      </ng-container>

      <ng-container matColumnDef="edit">
        <th mat-header-cell *matHeaderCellDef class="mat-column-edit"></th>
        <td mat-cell *matCellDef="let row">
          <button mat-raised-button (click)="openEditDialog(row)">Edit</button>
        </td>
      </ng-container>

      <mat-header-row *matHeaderRowDef="displayedColumnsA"></mat-header-row>
      <mat-row *matRowDef="let row; columns: displayedColumnsA;" matRipple class="element-row" [cdkDetailRow]="row"
        [cdkDetailRowTpl]="tpl"></mat-row>
    </mat-table>

This is my component code:

openEditDialog(data) {
    const editDialogConfig = new MatDialogConfig();

    editDialogConfig.disableClose = true;
    editDialogConfig.autoFocus = true;
    editDialogConfig.width = "900px";

    editDialogConfig.data = data;

    const dialogRef = this.editDialog.open(EditDialogComponent, editDialogConfig);

    dialogRef.afterClosed().subscribe(result => {
      console.log("dialog closed");
      this.dialogData = result;
      console.log(this.dialogData);

      let headers = new HttpHeaders({
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + this.authService.getToken()
      });
      let options = { headers: headers };

      this.http.post<CertData>(`http://localhost:8102/certtracker/certs/update`, this.dialogData, options)
        .subscribe(response => {
          console.log(response);
        });
    })
  }
}
CNDyson
  • 1,687
  • 7
  • 28
  • 63

1 Answers1

0

Ok I couldn't understand your question, but if you mean avoid to refresh the page when you update the datasource and you want to show the new rows, edit, etc.. I implemented a Database class:

export class DatabaseName {
  dataChange: BehaviorSubject<YourModel[]> = new BehaviorSubject<YourModel[]>([]);

  get data(): YourModel[] {
    return this.dataChange.value;
  }

  set data(value: YourModel[]) {
    this.dataChange.next(value);
  }

  constructor() { }

  addShareholder(shareholder: YourModel) {
    const copiedData = this.data.slice();
    copiedData.push(shareholder);
    this.dataChange.next(copiedData);
  }

  editShareholder(shareholder: YourModel, index: number) {
    const copiedData = this.data.slice();
    copiedData.splice(index, 1, shareholder);
    this.dataChange.next(copiedData);
  }

  deleteShareholder(index: number) {
    const copiedData = this.data.slice();
    copiedData.splice(index, 1);
    this.dataChange.next(copiedData);
  }
}

export class DataSourceName extends DataSource<YourModel> {

  constructor(private DBname: DatabaseName) {
    super();
  }


  connect(): Observable<YourModel[]> {
    return this.DBname.dataChange;
  }

  disconnect() { }
}

You must use a BehaviorSubject, I saw this holy code from a example 5 months ago

this is the entire example, this saved my life: https://github.com/marinantonio/angular-mat-table-crud

AndresSp
  • 176
  • 3
  • 16
  • Thanks, you have the idea of what I'm trying to do, but I don't understand how to implement your answer. – CNDyson Feb 07 '19 at 16:47
  • I feel you, its complicating but I tried all. You must use it below your parent code and when you need to edit for example: `dialogRef.afterClosed().subscribe(result => { //console.log('Closing...') if (!this.backDropClicked) { if(result){ this.database.editShareholder(result, index); } } this.backDropClicked = false; });` – AndresSp Feb 07 '19 at 16:58
  • its very easy, just instance the database class in the parent. I gave you a complete example, its a very good example – AndresSp Feb 07 '19 at 17:00
  • Ok, I'm trying to implement your example. Where does `backDropClicked` go though? Where should it be defined and referenced? – CNDyson Feb 07 '19 at 17:40
  • I used it like a boolean flag. If the user click on backdrop or press ESC I changed to true, but its my case.. something like this `dialogRef.backdropClick().subscribe((e) => { this.backDropClicked = true; dialogRef.close(); });` `dialogRef.keydownEvents().subscribe((e) => { if (e.key === 'Escape') { this.backDropClicked = true; dialogRef.close(); } }) ` – AndresSp Feb 07 '19 at 18:46