2017-09-29 110 views
0

我正在尝试在typescript 2.3.3中观察数组,并且我正在使用rxjs。我的目标是每次更改数组时都要运行一个方法。让我先澄清一些代码,然后再告诉你我尝试了什么。每次数组发生变化时发生Typscript火灾事件

rows: any[] = [] 
rows.push('test1') //fired event now 
rows.splice(0,1) //fire event now 
rows = [] // fire event now 

基本上,如果这个属性有变化,那么我想要一个事件调用。

我研究了Rx.Observable,并想出了一些不同的东西。

  1. Rx.Observable.from(this.rows)然后订阅它,但订阅永远不会被触发。
  2. Rx.Observable.of(this.rows)然后订阅它,这只会触发订阅1次。

    我认为Rx.Observable是去这里的路,但我不知道如何得到这个每次火事件。 感谢您的咨询

回答

0

我最终创建了一个ObservableArray类,它将触发事件并在其中具有订阅方法。我将在这里发布,以便有此问题的人也可以使用它。

export class ObservableArray { 
onArrayChanges: EventEmitter<any> = new EventEmitter(); 
onRemovedItem: EventEmitter<any> = new EventEmitter(); 
onAddedItem: EventEmitter<any> = new EventEmitter(); 

onComponentChanges: EventEmitter<any> = new EventEmitter(); 

length(): number { 
    return this.collection.length; 
} 

private collectionCount: number = 0; 
private isStartup:boolean=true; 
constructor(public array: any[]) { 
    this.onComponentChanges.subscribe(data => { 
     this.array = data; 
     this.onChanges(); 
    }); 
} 

private collection: any[] = []; 
private subscriptions: any[] = []; 

onChanges(): void { 
    let collectionModel = new CollectionModel(); 
    collectionModel.originalValue = this.collection; 
    collectionModel.newValue = (this.isStartup)?this.collection:this.array; 
    collectionModel.isRecordAdded = this.isAddedItem(); 
    collectionModel.isRecordRemoved = this.isRemovedItem(); 

    this.collectionCount = this.collection.length; 

    if (this.isAddedItem()) { 
     this.onAddedItem.emit(collectionModel); 
    } 

    if (this.isRemovedItem()) { 
     this.onRemovedItem.emit(collectionModel); 
    } 

    if (this.isChanged()) { 
     this.updateCollection(); 
     this.onArrayChanges.emit(collectionModel); 
     this.publish(collectionModel); 
     this.isStartup = false; 
    } 
} 
private isChanged(): boolean { 
    let isChanged = false; 
    if (this.array) { 
     isChanged = this.array.length !== this.collectionCount; 
    } 
    return isChanged || this.isStartup; 
} 
private isAddedItem(): boolean { 
    let isAddedItem = false; 
    if (this.array) { 
     isAddedItem =this.array.length > this.collectionCount; 
    } 
    return isAddedItem; 
} 
private isRemovedItem(): boolean { 
    let isRemoved = false; 
    if (this.array) { 
     isRemoved = this.array.length < this.collectionCount; 
    } 
    return isRemoved; 
} 

private updateCollection() { 
    this.collection = this.array; 
} 

    private publish(payload?: any) { 
     for (let callback of this.subscriptions) { 
      callback(payload); 
     } 
    } 

    subscribe(callback: (payload?: any) => void) { 
     this.subscriptions.push(callback); 
    } 
} 

export class CollectionModel { 
    originalValue: any[] = []; 
    newValue: any[] = []; 
    isRecordAdded: boolean = false; 
    isRecordRemoved: boolean = false; 
} 

如果你真的想你可以在我的情况下,让这个和ObservableArray<T>但我不认为我需要做到这一点。

我希望这可以帮助他人。 :)

0

尝试使用“蔓延”,而不是“推”

rows = [...rows,"test"] 
2

看起来Proxy可能适合该法案。一些初步测试表明,大多数就地Array存取器(如splicesortpush触发Proxy制定者,所以你也许能在侧容易发出值:

const subj: Subject<TItem> = new Subject(); // whatever TItem is convenient for you 
const rows: Array<T> = new Proxy([], { 
    set: function(target: Array<T>, idx: PropertyKey, v: T): boolean { 
     target[idx] = v; 
     this.subj.onNext(/* TItem-typed values here */); 
     return true; 
    } 
}); 

注意非常好(总的来说我感到惊讶),TypeScript强制new Proxy(Array<T>, ...)Array<T>,所以你所有的数组操作仍然是输入的!不利的一面是,你很可能会被事件淹没,特别是处理操作设置多次,例如sort,对此您可以预期O(n lg n)通知。

相关问题