I am trying to develop a desktop app using Electron with Angular in front-end. It utilizes Node mssql package in back-end to query a database, and should present retrieved data in somewhat desktop-looking UI - for the sake of this topic, let's say it is going to be visualised in table.
For now, until i will figure it out, the app presents like this:
Has text input to provide direct sql query, button to send it , and table to iterate through resultset.
Component's template:
<input type="text" id="queryInput" margin="5,5,5,5" [placeholder]="placeholder" [(ngModel)]="queryTerm" />
<button (click)="onQuery()" margin="5,5,5,5">
Execute
</button>
<table id="dataTable" margin="5,5,5,5" *ngFor="let item of shipments | async">
<tr>
<td>{{item.WMSObjectId}}</td>
<td>{{item.ShipNr}}</td>
<td>{{item.SupplyLetterNr}}</td>
<td>{{item.ArrivPeriodStartDT}}</td>
</tr>
</table>
Here is the component class:
export class AppComponent implements OnInit {
title = 'Curiosity';
placeholder: string = 'Type query in here';
queryTerm: string = "";
queryResult: IShipment[] = [];
shipments: Observable<IShipment[]> | undefined;
constructor(private _sqlClientService: SQLClientService) {}
ngOnInit(): void {
this.shipments = new Observable<IShipment[]>((observer: Observer<IShipment[]>) => {
observer.next(this.getQueryResults());
});
}
onQuery(): void {
this._sqlClientService.sqlQuery(this.queryTerm, (response: IResponseObject) => this.updateResultSet(response));
}
updateResultSet(response : IResponseObject) : void{
this.queryResult = response.recordset;
console.log(this.queryResult);
}
getQueryResults() : IShipment[]{
return this.queryResult;
}
}
The problem that im struggling to overcome is to let the UI know, that there is data to present, so *ngFor could populate the table.
I can see that data retrieval is completed, because updateResultSet is showing it in the console, but i don't quite understand how to push it to UI.
How exactly do i trigger next()?
Once i used setInterval(() => observer.next(this.getQueryResults()),1000);
just to test it, and THEN it works, but that's not a correct way ofcourse.
CodePudding user response:
I would use a BehaviorSubject
to accomplish the desired behavior. It would be best to put it in a separate service and expose it asObservable
instead of managing it in the component:
export class AppComponent implements OnInit {
title = 'Curiosity';
placeholder: string = 'Type query in here';
queryTerm: string = '';
queryResult = new BehaviorSubject<IShipment[]>([]);
constructor(private _sqlClientService: SQLClientService) {}
ngOnInit(): void {}
onQuery(): void {
this._sqlClientService.sqlQuery(
this.queryTerm,
(response: IResponseObject) => this.updateResultSet(response)
);
}
updateResultSet(response: IResponseObject): void {
this.queryResult.next(response.recordset);
console.log(this.queryResult);
}
}
And the relevant part of the template:
<table id="dataTable" margin="5,5,5,5" *ngFor="let item of queryResult | async">
CodePudding user response:
If you import ChangeDetectorRef in the constructor and use it, would this help?
https://angular.io/api/core/ChangeDetectorRef
constructor(private _sqlClientService: SQLClientService, private _changeDetectorRef ChangeDetectorRef) {}
updateResultSet(response: IResponseObject): void {
this.queryResult.next(response.recordset);
_changeDetectorRef.detectChanges();
console.log(this.queryResult);
}