I am struggling with an Angular service that contains an array of custom objects and an observable of this array. An external component subscribes to the observable but does not respond when the list is modified. Additionally, the mat-table, which uses the observable as its data source, also does not update.
The service utilizes a gRPC stream to fetch data:
export class ScanService {
private scanClient: ScanClient = new ScanClient('http://' + window.location.hostname + ':8080', null, null);
private results: ItemModel[] = [];
readonly results$ = from(this.results);
constructor() { }
start(ip: string): boolean {
let stream = this.scanClient.listen(ip, {});
stream.on('data', (response) => {
this.results.push({
name: response.getName(),
type: response.getType(),
});
console.log('stream got item: ' + response.getName());
});
}
}
The consumer:
export class ScanComponent implements OnInit {
//...
results$: Observable<ItemModel[]>;
constructor(private scanService: ScanService) { }
ngOnInit() {
this.results$ = this.scanService.results$;
this.results$.subscribe({next: function(results){console.log('subscriber got item: ', results);}});
}
onScan() {
this.scanService.start(this.ip);
}
}
<table mat-table [dataSource]="results$" class="mat-elevation-z8">
In the console output, I can see "stream got item" for each item, but there is no "subscriber got item" message, and the mat-table remains empty.
EDIT:
I have another example using `of` that works correctly. The only difference is that the gRPC call returns an object directly instead of a stream.
Service:
export class DiscoveryService {
private deviceList: DeviceModel[] = [];
private discoveryClient: DiscoveryClient = new DiscoveryClient('http://' + window.location.hostname + ':8080', null, null);
constructor() {}
getDeviceList(): void {
this.discoveryClient.devices(new EmptyProto(), {}, (err, reply) => {
const pbDeviceList = reply.getDevicesList();
for (const pbDevice of pbDeviceList) {
this.deviceList.push({ ip: pbDevice.getIp()});
}
});
}
observeDeviceList(): Observable<DeviceModel[]> {
return of(this.deviceList);
}
}
Consumer:
export class DeviceListComponent implements OnInit {
deviceList$: Observable<DeviceModel[]>;
constructor(private discoveryService: DiscoveryService) { }
ngOnInit() {
this.deviceList$ = this.discoveryService.observeDeviceList();
this.discoveryService.getDeviceList();
}
}
<mat-nav-list *ngFor="let device of deviceList$ | async">