Search code examples
angularangular-materialresetmat-table

How can I refresh Angular Material Table data back to it's initial state within the page?


Some notes:

  • My goal is to implement some "discard" and "save" changes type of functionality.
  • The "companyService" service calls an api which fetches the top "X" companies (in this case, 5) from a database.
  • The table gets populated through a DataSource instance.
  • This application will eventually be put into production.

So the user will be able to toggle the on/off buttons and select "allow" or "deny" from the dropdown menu. Upon a user interacting with these buttons I would like to display some text next to the save button saying that there are unsaved changes. But the part that I can't seem to figure out is how to handle the click event on the Discard Changes button and "reset" the data in the table back to its initial state after the user makes some changes. I'm just confused because the data source of the table is tied to a database on the server.

If you could maybe give me specific advice on using DataSource or just point me in the right direction it would be much appreciated!

[![][1]][1]

My component class references this CompanyDataSource class to populate the table.

company-config-table.component.ts

HTML CODE

<table mat-table #companyTable [trackBy]="trackByIndex" [dataSource]="dataSource" matSort class="mat-elevation-z8">
        
        <!-- Client ID Column -->
        <ng-container matColumnDef="clientId">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Client ID </th>
        <td mat-cell *matCellDef="let company">{{ company.clientId }}</td>
        <td mat-footer-cell *matFooterCellDef>
            <button mat-button (click)="onDiscardChanges()">Discard Changes</button>
        </td>
        </ng-container>

        <!-- Name Column -->
        <ng-container matColumnDef="name">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Company </th>
        <td mat-cell *matCellDef="let company"> {{ company.name }}</td>
        <td mat-footer-cell *matFooterCellDef></td>
        </ng-container>


        <!-- Include Bsa Details Column -->
        <ng-container matColumnDef="includeBsaDetails">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Include BSA Details </th>
        <td mat-cell *matCellDef="let company">
            <mat-button-toggle-group #toggleGroup="matButtonToggleGroup">
                <mat-button-toggle class="on"   [checked]="company.includeBsaDetails"  [value]="true"  (change)="onIncludeBsaDetailsButtonToggleEvent($event, company)">ON</mat-button-toggle>
                <mat-button-toggle class="off"  [checked]="!company.includeBsaDetails" [value]="false" (change)="onIncludeBsaDetailsButtonToggleEvent($event, company)">OFF</mat-button-toggle>
            </mat-button-toggle-group>
        </td>
        <td mat-footer-cell *matFooterCellDef></td>
        </ng-container>

        <!-- Bsa Tool Permission Column -->
        <ng-container matColumnDef="bsaToolPermission">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Implicit BSA Permission </th>
        <td mat-cell *matCellDef="let company">
            <mat-form-field>
                <mat-select [(value)]="company.bsaToolPermission" (change)="onBsaToolPermissionSelectChangeEvent($event, company)">
                  <mat-option value="ALLOW">ALLOW</mat-option>
                  <mat-option value="DENY">DENY</mat-option>
                </mat-select>
            </mat-form-field>
        </td>
        <td mat-footer-cell *matFooterCellDef>
            
        </td>
        </ng-container>

        <!-- Auto Lock Confirmation Column -->
        <ng-container matColumnDef="autoLockConfirm">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Automated Lock Confirmation </th>
        <td mat-cell *matCellDef="let company">
            <mat-button-toggle-group #toggleGroup2="matButtonToggleGroup">
                <mat-button-toggle class="on"   [checked]="company.autoLockConfirm"  [value]="true"  (change)="onAutoLockConfirmButtonToggleEvent($event, company)">ON</mat-button-toggle>
                <mat-button-toggle class="off"  [checked]="!company.autoLockConfirm" [value]="false" (change)="onAutoLockConfirmButtonToggleEvent($event, company)">OFF</mat-button-toggle>
            </mat-button-toggle-group>
        </td>
        <td mat-footer-cell *matFooterCellDef>
            <button mat-button>Save Changes</button>
        </td>
        </ng-container>
    
    
        <!-- Table Configuration for rows, header, and footer -->
        <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
        <tr mat-row *matRowDef="let row; columns: columnsToDisplay;"></tr>
        <tr mat-footer-row *matFooterRowDef="columnsToDisplay"></tr>
    </table>

Solution

  • Can't you just call loadCompanies() to refetch the data from the server? That should replace the table to the values that the database has.

    If this doesn't work for some reason, another idea would be to keep track of the original data, and then reset the grid to that original data.

    class CompanyDataSource extends DataSource<any> {
        public companiesSubject = new BehaviorSubject<Company[]>([]);
        public originalData: Company[];
        constructor(private companyService: CompanyService) {
            super();
        }
        connect(): Observable<Company[]> {
            return this.companiesSubject.asObservable();
        }
        disconnect() {
            this.companiesSubject.complete();
        }
        loadCompanies(amount: number) {
            this.companyService.GetTopXCompanies(amount).subscribe((companies) => {
                this.originalData = companies;
                const deepCopyData = JSON.parse(JSON.stringify(companies));
                this.companiesSubject.next(deepCopyData);
            });
        }
        discardChanges() {
            const deepCopyData = JSON.parse(JSON.stringify(this.originalData));
            this.companiesSubject.next(deepCopyData);
        }
    }