Reputation: 209
I have been writing a code to get data from my server via websockets and display it in Angular mat-table. I am having issues as the table data is not refreshing. I am able to display the data in a simple table. But the same is not getting displayed in a mat-table. In one of the blogs, i read to use _updateChangeSubscription / _renderChangesSubscription but nothing works. I even tried using @ViewChild component to trigger the data refresh. Even that is not working. below are my app.compnent.html and app.component.ts for reference
app.component.html
<!-- Simple table where data is getting displayed-->
<div>
<table border="10">
<thead>
<tr>
<th> Id</th>
<th> Name</th>
<th> Output </th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of result">
<th>{{ data.id }}</th>
<td>{{ data.name }}</td>
<td>{{ data.output }}</td>
</tr>
</tbody>
</table>
</div>
<!-- mat-table where data is not getting displayed -->
<mat-table [dataSource]="datasource">
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef> id. </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.id }} </mat-cell>
</ng-container>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.name }} </mat-cell>
</ng-container>
<ng-container matColumnDef="output">
<mat-header-cell *matHeaderCellDef> Output </mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.output }} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.styl']
})
export class AppComponent {
title = 'web socket example';
private serverUrl = 'http://localhost:8080/server'
private stompClient;
@ViewChild(MatTable) table : MatTable<any>;
result = [];
displayedColumns: string[] = ['id', 'name', 'output'];
datasource : MatTableDataSource<Element[]>;
constructor(){
this.initializeWebSocketConnection();
}
stompSucessCallBack = () => {
this.stompClient.subscribe("/messages", (message) => {
if(message.body) {
this.result.push(JSON.parse(message.body));
this.datasource.data.push(message.body);
this.datasource._updateChangeSubscription;
this.datasource._renderChangesSubscription;
this.table.renderRows;
console.log("******");
console.trace(this.datasource.data);
}
});
}
initializeWebSocketConnection(){
let ws = new SockJS(this.serverUrl);
this.stompClient = Stomp.over(ws);
this.datasource = new MatTableDataSource();
let that = this;
this.stompClient.connect({}, that.stompSucessCallBack);
}
}
packge.json
"dependencies": {
"-": "0.0.1",
"@angular/animations": "~9.1.7",
"@angular/cdk": "^9.2.4",
"@angular/common": "~9.1.7",
"@angular/compiler": "~9.1.7",
"@angular/core": "~9.1.7",
"@angular/forms": "~9.1.7",
"@angular/material": "^9.2.4",
"@angular/platform-browser": "~9.1.7",
"@angular/platform-browser-dynamic": "~9.1.7",
"@angular/router": "~9.1.7",
"jquery": "^3.5.1",
"net": "^1.0.2",
"rxjs": "~6.5.4",
"sockjs-client": "^1.4.0",
"stompjs": "^2.3.3",
"tslib": "^1.10.0",
"zone.js": "~0.10.2"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.901.6",
"@angular/cli": "~9.1.6",
"@angular/compiler-cli": "~9.1.7",
"@types/node": "^12.11.1",
"@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "^5.1.2",
"jasmine-core": "~3.5.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~5.0.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~2.1.0",
"karma-jasmine": "~3.0.1",
"karma-jasmine-html-reporter": "^1.4.2",
"protractor": "~5.4.3",
"ts-node": "~8.3.0",
"tslint": "~6.1.0",
"typescript": "~3.8.3"
}
Upvotes: 1
Views: 1408
Reputation: 66
I ran across a similar problem recently.. There are a couple differences between your solution and my working one.
First- Your data source initialization:
this.datasource = new MatTableDataSource<Element>([]);
And in your callback:
let result = <Element>JSON.parse(message.body);
const datasource = this.datasource.data;
datasource.push(result);
this.datasource.data = datasource;
Component:
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.styl']
})
export class AppComponent {
title = 'web socket example';
private serverUrl = 'http://localhost:8080/server'
private stompClient;
displayedColumns: string[] = ['id', 'name', 'output'];
datasource : MatTableDataSource<Element>;
constructor(){
this.initializeWebSocketConnection();
}
stompSucessCallBack = () => {
this.stompClient.subscribe("/messages", (message) => {
if(message.body) {
let result = <Element>JSON.parse(message.body);
const datasource = this.datasource.data;
datasource.push(result);
this.datasource.data = datasource;
}
});
}
initializeWebSocketConnection(){
let ws = new SockJS(this.serverUrl);
this.stompClient = Stomp.over(ws);
this.datasource = new MatTableDataSource<Element>([]);
let that = this;
this.stompClient.connect({}, that.stompSucessCallBack);
}
}
If this still fails, it could be a mapping error... I have a model for my JSON to parse to. I suggest you do something similar.
It could also be a rendering issue, not likely to be the problem, but just a small html difference between our two solutions:
Try replacing mat-header-cell with th:
<th mat-header-cell *matHeaderCellDef>
And mat-cell with td:
<td mat-cell *matCellDef="let element">
Upvotes: 2