I'm having trouble synchronizing data from an observable in a service with a component that consumes the data. The data service calls an api service when it is created to build a list of devices it gets from a server. This appears to be working fine as the device list is built in the data service.
import { Injectable } from '@angular/core';
import { ApiService } from './api.service';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class DeviceManagerService {
devicesInfo = null;
deviceInfo = null;
devices = [];
constructor(private apiService: ApiService ) {
this.apiService.getDeviceStatus().subscribe((resp) => {
this.devicesInfo = resp;
console.log('DeviceManager: deviceInfo: ',this.devicesInfo);
this.buildDeviceTable(resp);
console.log('devices[]=', this.devices);
});
}
buildDeviceTable(devicesInfo) {
devicesInfo.record.forEach( device => {
console.log('record.devid= ', device.devid);
if ( this.devices.indexOf(device.devid) > -1) {
//console.log('element ', device.devid, ' already in devices array');
}
else {
//this.devices.push({ device: device.devid });
this.devices.push(device.devid);
//console.log('added ', device.devid, ' to devices array');
}
})
}
getDevices(): Observable<string[]> {
let data = new Observable<string[]>(observer => {
observer.next(this.devices);
});
return data;
}
}
In my component I want to display that list of devices in a mat-table. I have the list of devices set up as an observable in the data service and the component subscribes to that. But when the subscribe function is run, the data is not returned in the observable- the array is empty and the forEach loop does not run to copy the device IDs from the observable into the local array that is used as the data source fo the mat-table.
import { DeviceManagerService } from './../../services/device-manager.service';
import { Component, OnInit } from '@angular/core';
import { MatTableModule, MatTableDataSource } from '@angular/material';
import { Observable } from 'rxjs';
@Component({
selector: 'app-devices',
templateUrl: './devices.component.html',
styleUrls: ['./devices.component.css']
})
export class DevicesComponent implements OnInit {
displayedColumns: string[] = ['deviceID'];
//devices = null;
devices=["test1","test2"];
deviceData = null;
constructor(private deviceManager: DeviceManagerService) {
this.deviceManager.getDevices().subscribe( devTable => {
console.log('devTable: length', devTable.length);
devTable.forEach( device => {
console.log('forEach: device: ', device);
});
console.log('devices: ', this.devices);
//this.devices = devTable;
});
}
ngOnInit() {
this.deviceData = new MatTableDataSource<any>(this.devices);
console.log('devicessComponent: ', this.deviceData);
}
}
devices remain at their default initialized value and never get assigned the values that come from the device manager. But the device manager has built the proper device list, for some reason it is not getting to the component via the subscribe function.
How do I make sure that the data is provided in the subscribe function?
Thanks....
this.deviceManager.getDevices()in your component the async request is not finished yet andthis.devicesin your service are still empty. The solution with theBehaviourSubjectfrom SnorreDan seems fine - ChrisY