I'm developing a WebApp with MEANStack, currently working on the Front End with Angular. My App simply reads SQL Data Tables and displays them on a browser in the form of Angular Tables.
Here's how it looks like:
Data Table Display MEANStack App
Unfortunately the Sort functionality does not work. Any idea why? Furthermore, how can I implement the "scroll left and right" functionality, given that my tables are a bit large?
Here's my code (Please do not hesitate to ask for more code):
tables-list.component.html
<mat-spinner *ngIf="isLoading"></mat-spinner>
<h1 class="mat-body-2">Process List </h1>
<mat-accordion multi="true" *ngIf="userIsAuthenticated && !isLoading">
<mat-expansion-panel>
<mat-expansion-panel-header>
Process List
</mat-expansion-panel-header>
<table mat-table [dataSource]="processTables" matSort class="mat-elevation-z8" *ngIf="userIsAuthenticated">
<!-- ProcessID Column -->
<ng-container matColumnDef="ProcessID">
<th mat-header-cell *matHeaderCellDef mat-sort-header> ProcessID </th>
<td mat-cell *matCellDef="let element"> {{element.ProcessID}} </td>
</ng-container>
<!-- ProcessName Column -->
<ng-container matColumnDef="ProcessName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> ProcessName </th>
<td mat-cell *matCellDef="let element"> {{element.ProcessName}} </td>
</ng-container>
<!-- PackageVersion Column -->
<ng-container matColumnDef="PackageVersion">
<th mat-header-cell *matHeaderCellDef mat-sort-header> PackageVersion </th>
<td mat-cell *matCellDef="let element"> {{element.PackageVersion}} </td>
</ng-container>
<!-- RobotType Column -->
<ng-container matColumnDef="RobotType">
<th mat-header-cell *matHeaderCellDef mat-sort-header> RobotType </th>
<td mat-cell *matCellDef="let element"> {{element.RobotType}} </td>
</ng-container>
<!-- PackagePath Column -->
<ng-container matColumnDef="PackagePath">
<th mat-header-cell *matHeaderCellDef mat-sort-header> PackagePath </th>
<td mat-cell *matCellDef="let element"> {{element.PackagePath}} </td>
</ng-container>
<!-- CreationTime Column -->
<ng-container matColumnDef="CreationTime">
<th mat-header-cell *matHeaderCellDef mat-sort-header> CreationTime </th>
<td mat-cell *matCellDef="let element"> {{element.CreationTime}} </td>
</ng-container>
<!-- Status Column -->
<ng-container matColumnDef="Status">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Status </th>
<td mat-cell *matCellDef="let element"> {{element.Status}} </td>
</ng-container>
<!-- Header and Row Declarations -->
<tr mat-header-row *matHeaderRowDef="displayedprocessTablesColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedprocessTablesColumns;"></tr>
</table>
</mat-expansion-panel>
</mat-accordion>
<br> <h1 class="mat-body-2">Applications List </h1>
<mat-accordion multi="true" *ngIf="userIsAuthenticated && !isLoading">
<mat-expansion-panel>
<mat-expansion-panel-header>
Applications List
</mat-expansion-panel-header>
<table mat-table [dataSource]="applicationsTables" matSort class="mat-elevation-z8" *ngIf="userIsAuthenticated">
<!-- ProcessName Column -->
<ng-container matColumnDef="ProcessName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> ProcessName </th>
<td mat-cell *matCellDef="let element"> {{element.ProcessName}} </td>
</ng-container>
<!-- PackageVersion Column -->
<ng-container matColumnDef="PackageVersion">
<th mat-header-cell *matHeaderCellDef mat-sort-header> PackageVersion </th>
<td mat-cell *matCellDef="let element"> {{element.PackageVersion}} </td>
</ng-container>
<!-- WorkflowsBelongingToProcess Column -->
<ng-container matColumnDef="WorkflowsBelongingToProcess">
<th mat-header-cell *matHeaderCellDef mat-sort-header> WorkflowsBelongingToProcess </th>
<td mat-cell *matCellDef="let element"> {{element.WorkflowsBelongingToProcess}} </td>
</ng-container>
<!-- ApplicationsBelongingToWorkflow Column -->
<ng-container matColumnDef="ApplicationsBelongingToWorkflow">
<th mat-header-cell *matHeaderCellDef mat-sort-header> ApplicationsBelongingToWorkflow </th>
<td mat-cell *matCellDef="let element"> {{element.ApplicationsBelongingToWorkflow}} </td>
</ng-container>
<!-- Header and Row Declarations -->
<tr mat-header-row *matHeaderRowDef="displayedApplicationsTablesColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedApplicationsTablesColumns;"></tr>
</table>
</mat-expansion-panel>
</mat-accordion>
tables.module.ts
import { NgModule } from "@angular/core";
import { ReactiveFormsModule } from "@angular/forms";
import { CommonModule } from "@angular/common";
import { RouterModule } from "@angular/router";
import { TableListComponent } from "./tables-list.component";
import { AngularMaterialModule } from "../angular-material.module";
@NgModule({
declarations: [TableListComponent],
imports: [
CommonModule,
ReactiveFormsModule,
AngularMaterialModule,
RouterModule
]
})
export class TablesModule {}
angular-material.module.ts
import { NgModule } from "@angular/core";
import {
MatInputModule,
MatCardModule,
MatButtonModule,
MatToolbarModule,
MatExpansionModule,
MatProgressSpinnerModule,
MatPaginatorModule,
MatDialogModule,
MatSelectModule,
MatListModule,
MatIconModule,
MatTableModule,
MatSortModule,
MatTabsModule,
MatAutocompleteModule,
MatBadgeModule,
MatBottomSheetModule,
MatButtonToggleModule,
MatCheckboxModule,
MatChipsModule,
MatStepperModule,
MatDatepickerModule,
MatGridListModule,
MatDividerModule,
MatMenuModule,
MatNativeDateModule,
MatProgressBarModule,
MatRadioModule,
MatRippleModule,
} from "@angular/material";
import { CdkTableModule } from "@angular/cdk/table";
import { CdkTreeModule } from "@angular/cdk/tree";
@NgModule({
exports: [
MatInputModule,
MatCardModule,
MatButtonModule,
MatToolbarModule,
MatExpansionModule,
MatProgressSpinnerModule,
MatPaginatorModule,
MatDialogModule,
MatSelectModule,
MatListModule,
MatIconModule,
MatTableModule,
MatSortModule,
MatTabsModule,
CdkTableModule,
CdkTreeModule,
MatAutocompleteModule,
MatBadgeModule,
MatBottomSheetModule,
MatButtonToggleModule,
MatCheckboxModule,
MatChipsModule,
MatStepperModule,
MatDatepickerModule,
MatDividerModule,
MatGridListModule,
MatMenuModule,
MatNativeDateModule,
MatProgressBarModule,
MatRadioModule,
MatRippleModule,
]
})
export class AngularMaterialModule {}
tables-list.component.ts:
import { Component, OnInit, OnDestroy, ViewChild } from "@angular/core";
import { ProcessTable, ApplicationsTable } from "./tables.model";
import { PageEvent, MatTableDataSource, MatSort } from "@angular/material";
import { Subscription } from "rxjs";
import { TablesService } from "./tables.service";
import { AuthService } from "../auth/auth.service";
@Component({
// We load the component via routing and therefore we do not need a selector
selector: "app-tables",
templateUrl: "./tables-list.component.html",
styleUrls: ["./tables-list.component.css"]
}) // Turn class into component by adding @Component Decorator
export class TableListComponent implements OnInit, OnDestroy {
processTables: ProcessTable[] = [];
applicationsTables: ApplicationsTable[] = [];
isLoading = false;
totalTables = 0;
tablesPerPage = 5;
currentPage = 1;
pageSizeOptions = [1, 2, 5, 10];
dataSource = new MatTableDataSource(this.processTables);
@ViewChild(MatSort) sort: MatSort;
displayedprocessTablesColumns: string[] = [
"ProcessID",
"ProcessName",
"PackageVersion",
"RobotType",
"PackagePath",
"CreationTime",
"Status"
];
displayedApplicationsTablesColumns: string[] = [
"ProcessName",
"PackageVersion",
"WorkflowsBelongingToProcess",
"ApplicationsBelongingToWorkflow"
];
userIsAuthenticated = false;
userId: string;
isAdmin: boolean;
private tablesSub: Subscription;
private authStatusSub: Subscription;
constructor(
public tablesService: TablesService,
private authService: AuthService
) {}
ngOnInit() {
this.isLoading = true;
this.dataSource.sort = this.sort;
this.tablesService.getProcessTables(this.tablesPerPage, this.currentPage);
this.userId = this.authService.getUserId();
this.tablesSub = this.tablesService
.getTableUpdateListener()
.subscribe((tableData: { processTables: ProcessTable[]; applicationsTables: ApplicationsTable[]; tableCount: number }) => {
this.isLoading = false;
this.totalTables = tableData.tableCount;
this.processTables = tableData.processTables;
this.applicationsTables = tableData.applicationsTables;
});
this.userIsAuthenticated = this.authService.getIsAuth();
// console.log("Is authenticated: " + this.userIsAuthenticated);
this.authStatusSub = this.authService
.getAuthStatusListener()
.subscribe(isAuthenticated => {
this.userIsAuthenticated = isAuthenticated;
});
}
onLogout() {
this.authService.logout();
}
ngOnDestroy() {
this.tablesSub.unsubscribe();
this.authStatusSub.unsubscribe();
}
}
Tables.service.ts:
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Subject } from "rxjs";
import { map } from "rxjs/operators";
import { Router } from "@angular/router";
import { environment } from "../../environments/environment";
import { ProcessTable, ApplicationsTable } from "./tables.model";
const BACKEND_URL = environment.apiUrl + "/tables/";
@Injectable({ providedIn: "root" })
export class TablesService {
private processTables: ProcessTable[] = [];
private applicationsTables: ApplicationsTable[] = [];
private tablesUpdated = new Subject<{ processTables: ProcessT