Angular 订阅可观察但运行时未准备好的数据
我无法将服务中的可观测数据与使用数据的组件同步。数据服务在创建时调用api服务,以生成从服务器获取的设备列表。由于设备列表是在数据服务中构建的,因此这似乎工作正常Angular 订阅可观察但运行时未准备好的数据,angular,observable,Angular,Observable,我无法将服务中的可观测数据与使用数据的组件同步。数据服务在创建时调用api服务,以生成从服务器获取的设备列表。由于设备列表是在数据服务中构建的,因此这似乎工作正常 import { Injectable } from '@angular/core'; import { ApiService } from './api.service'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export
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;
}
}
从'@angular/core'导入{Injectable};
从“/api.service”导入{ApiService};
从“rxjs”导入{Observable};
@注射的({
providedIn:'根'
})
导出类设备管理服务{
DeviceInfo=null;
deviceInfo=null;
设备=[];
构造函数(私有apiService:apiService){
this.apiService.getDeviceStatus().subscribe((resp)=>{
this.devicesInfo=resp;
console.log('DeviceManager:deviceInfo:',this.deviceInfo);
此.buildDeviceTable(resp);
console.log('devices[]=',this.devices);
});
}
buildDeviceTable(设备信息){
DeviceInfo.record.forEach(设备=>{
console.log('record.devid=',device.devid');
if(this.devices.indexOf(device.devid)>-1){
//log('element',device.devid',已经在设备数组中');
}
否则{
//this.devices.push({device:device.devid});
这个.devices.push(device.devid);
//log('added',device.devid',to devices array');
}
})
}
getDevices():可观察{
让数据=新的可观察对象(观察者=>{
observer.next(本设备);
});
返回数据;
}
}
在我的组件中,我希望在mat表中显示该设备列表。我将设备列表设置为数据服务中的可观察设备,组件订阅了该列表。但是,当subscribe函数运行时,数据不会在可观察对象中返回-数组为空,并且forEach循环不会运行以将设备ID从可观察对象复制到用作mat表数据源的本地数组中
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);
}
}
从“/../../services/device manager.service”导入{devicemanager服务};
从“@angular/core”导入{Component,OnInit};
从“@angular/material”导入{MatTableModule,MatTableDataSource};
从“rxjs”导入{Observable};
@组成部分({
选择器:“应用程序设备”,
templateUrl:'./devices.component.html',
样式URL:['./devices.component.css']
})
导出类DeviceComponent实现OnInit{
displayedColumns:string[]=['deviceID'];
//设备=空;
设备=[“test1”、“test2”];
deviceData=null;
构造函数(专用设备管理器:设备管理器服务){
this.deviceManager.getDevices().subscribe(devTable=>{
log('devTable:length',devTable.length);
devTable.forEach(设备=>{
log('forEach:device:',device);
});
console.log('devices:',this.devices);
//这个。设备=可开发的;
});
}
恩戈尼尼特(){
this.deviceData=新MatTableDataSource(this.devices);
console.log('DeviceComponent:',this.deviceData);
}
}
设备保持其默认的初始化值,并且永远不会被分配来自设备管理器的值。但是设备管理器已经建立了正确的设备列表,由于某些原因,它无法通过subscribe函数访问组件
如何确保在subscribe函数中提供数据
谢谢……我不是100%肯定,但我相信它不起作用的原因是,在将数据传递给它之前,需要订阅你的observable。在代码中,首先使用observer.next(this.devices)传递数据,然后订阅。订阅时,数据已发送,事件已完成 有两种方法可以解决这个问题,一种是使用行为主体
devices$=new behavior subject([])代码>
this.devices$.next(this.devices)代码>
this.deviceManager.getDevices().subscribe(
替换为this.deviceManager.devices$.subscribe(
您应该使用
ReplaySubject
或BehaviorSubject
。如果您只希望它在发出第一个值时发出一个值,则将使用第一个。如果您希望它具有默认值(例如,空数组),则使用后一个
您甚至可以将服务更新为完全使用流,这将始终保持数据的最新状态,并大大减少.subscribe
的使用,这是导致内存泄漏(未关闭的订阅)的一大原因:
由于您现在使用的是streams,因此MatTableDataSource
的使用变得过时,因为您只需将observable as数据源传递给mat表:
export class DevicesComponent {
displayedColumns: string[] = ['deviceID'];
readonly devices$ = this.deviceManager.devices$;
constructor(private deviceManager: DeviceManagerService) {}
}
如您所见,我没有使用行为子对象
或ReplaySubject
,但我使用了shareReplay()
操作符。它基本上在ReplaySubject
中转换一个可观察对象,并在订阅者之间共享订阅
但是请注意,使用shareReplay(1)
时应谨慎。如果您有一个未完成的可观察对象,即使组件被销毁,订阅也不会结束。您可以添加一个takeUntil(//销毁可观察对象)
,或者将其更改为shareReplay({refCount:true,bufferSize:1})
。一旦订阅计数达到0,后者将重新启动原始的可观察的
,并在之后再次订阅。不过,好的是,事情确实得到了清理。因此..这只是一个脚注:)
我认为当您订阅组件中的
this.deviceManager.getDevices()
时,异步请求尚未完成,您服务中的this.devices
仍然是空的。带有行为主题的解决方案
export class DevicesComponent {
displayedColumns: string[] = ['deviceID'];
readonly devices$ = this.deviceManager.devices$;
constructor(private deviceManager: DeviceManagerService) {}
}