将动态数组的动态数组转换为可观察的

时间:2019-03-16 18:09:03

标签: rxjs reactivex

我有一个动态数组结构。具体来说就是Google Maps的MVCArray。该结构具有常规的put,get,remove方法以及一个addListener来侦听任何更改。库方法(Polygon#getPaths)返回LatLngs的MVCArray的MVCArray,因为多边形可以具有任意数量的路径,并且每个路径可以具有任意数量的顶点。

我的目标是转换生成PolygonPathEvent的Observable,当父MVCArray或任何子MVCArray更改时将触发。

创建可观察对象

首要业务是将addListener转换为Observables。

private createMVCEventObservable<T>(array: MVCArray<T>): Observable<[T[], string, number, T?]>{
    const eventNames = ['insert_at', 'remove_at', 'set_at'];
    return fromEventPattern(
      (handler: Function) => eventNames.map(evName => array.addListener(evName,
        (index: number, previous?: LatLng) => this._zone.run(() => handler.apply(array, [[array.getArray(), evName, index, previous]])))),
      (handler: Function, evListeners: MapsEventListener[]) => evListeners.forEach(evListener => evListener.remove()));
  }

结合观察者

现在要合并,看来我们需要使用combineLatest

const pathsChanges$ = this.createMVCEventObservable(paths);
const pathChanges$ = combineLatest(paths.getArray().map(this.createMVCEventObservable));
return combineLatest(pathChanges$, pathsChanges$, (pathArr, paths) => 
  new PolygonPathEvent(pathArr, paths);
);

问题在于MVCArray的父MVCArray可以更改,但是combineLatest接收一个静态数组。因此,当添加新路径时,我不知道如何使返回的Observable也监听此新路径。同样,如果删除了路径,我不知道如何使返回的可观察者从已删除的路径退订。

输给主题(错误的方法)

我考虑过返回一个主题,并且只要父MVCArray<MVCArray<LatLng>>发生变化,就将其订阅到其他可观察对象。

const retVal: Subject<PolygonPathEvent> = new Subject();
const pathsChanges$ = this.createMVCEventObservable(paths);
const pathChanges$ = combineLatest(paths.getArray().map(this.createMVCEventObservable));
let latestSubscription = combineLatest(pathChanges$, pathsChanges$, (pathArr, paths) => 
  new PolygonPathEvent(pathArr, paths)
).subscribe(retVal);

pathsChanges$.pipe(tap( ([arrays, event, index, previous]) => {
  latestSubscription.unsubscribe();
  latestSubscription = combineLatest(pathChanges$, pathsChanges$, (pathArr, paths) => 
  new PolygonPathEvent(pathArr, paths)
  ).subscribe(retVal);
} ));

return retVal;

这可行,问题在于对原始Observables(和addListener)的订阅恰好在此方法中发生,而不是在订阅返回的Observable时发生。

结论

为此我需要某种运算符。

1 个答案:

答案 0 :(得分:1)

如果我正确理解您的问题,则可能有空间使用switchMap来解决问题。

您说“ 问题是MVCArray的父MVCArray可以更改,但是CombineLatest采用静态数组”。我认为您引用的静态数组是pathChanges$ Observable发出的数组,该数组在代码段的开头全部创建一次,并且在MVCArray的父MVCArray更改时不会更新。

如果我的理解是正确的,我们需要做的是提供一种方法来通知MVCArray的父MVCArray的更改事件,并在发生此类事件的任何时间,再次使用combineLatest函数来执行新的更新数组。

这可以通过类似于以下内容的逻辑来实现

const pathsChanges$ = this.createMVCEventObservable(paths);

pathsChanges$
.pipe(
   switchMap(() => combineLatest(paths.getArray().map(this.createMVCEventObservable))),
   map(pathArr => new PolygonPathEvent(pathArr, paths))
)

此逻辑假定变量paths从外部传递到此逻辑中。

我无法重提此案,因此即使我希望能对您有所帮助,我也不确定我的答案是否可以解决您的问题。