RxJS可观察到的数组无法正常工作

时间:2019-11-18 12:44:50

标签: angular typescript rxjs

我有一个角度服务,它有一个array of custom objects和一个observable of这个数组。 可观察对象的外部组件subscribes,但是当列表得到更改时不响应。
另外,对于observable不会起反应的data source设置为mat-table

服务(使用gRPC流获取数据):

export class ScanService {
    private scanCient: 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.scanCient.listen(ip, {});

    stream.on('data', (response) => {
        this.results.push({
            name: response.getName(),
            type: response.getType(),
        });

        console.log('stream got item: ' + response.getName());
        }
    }
}

消费者:

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">

console output中,我看到每个项目的stream got item,但没有subscriber got item,并且mat-table仍然为空。

编辑:

我有一个使用of的类似示例,该示例似乎可以正常工作。
区别在于gRPC调用直接返回一个对象,而不是流。

服务:

export class DiscoveryService {
    private deviceList: DeviceModel[] = [];
    private discoveryCient: DiscoveryClient = new DiscoveryClient('http://' + window.location.hostname + ':8080', null, null);

    constructor() {
    }

    getDeviceList(): void {
       this.discoveryCient.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);
    }
  }

消费者:

export class DeviceListComponent implements OnInit {
  deviceList$: Observable<DeviceModel[]>;

  constructor(private discoveryService: DiscoveryService) { }

  ngOnInit() {
    // First get the observable to the list(which is still empty)
    this.deviceList$ = this.discoveryService.observeDeviceList();

    // Then tell the service to populate the list
    this.discoveryService.getDeviceList();
  }
}
 <mat-nav-list *ngFor="let device of deviceList$ | async">

1 个答案:

答案 0 :(得分:0)

积累评论中其他有用声音已经告诉您的内容:

您在这里面临两个问题。

of()vs from()

我在这里指的是another question。基本上,of([[1,2,3])创建一个可观察对象,它将像在数组上一样发出“ [1,2,3]”,因此您将得到一个发出,而from([1,2,3])将发出最后是“ 1”,然后是“ 2”和“ 3”。从您的result$的使用情况来看,我猜您想使用of()

主题vs可观察

您希望将result-Array的更新发布给result$-Observable的订户,但是Observable一旦发出所有值,便完成了,因此它将自动完成发出订阅时存在的静态数据后,请取消订阅。 一个简单的解决方法是使用Subjects尤其是BehaviourSubjects而不是Observables。它们具有类似于发布商的特性。

const result$ = new BehaviourSubject<ItemModel[]>(this.result);

这些向所有新订阅者发出最后发出的值,并且还允许您通过调用其next()方法向其订阅者释放新数据。 因此,您需要致电

result$.next(newValue);

代替

result = newValue;