As described in the questions, I need an ObservableList contain an Array , and not extend it, as Jim did in his complex answer. And, surprisingly, I found that this can be easily achieved by wrapping the original Array operations .
One of the limitations is that the index operation is not responsive in my implementation, because I could not find the right way to capture index operations. If you have a better idea, feel welcome to tell me! Xd
Here's the full implementation.
export class ObservableList { list: Array<any>; private _observer: Array<ObserverList>; constructor(list?: Array<any>) { this.list = list || []; this._initList(); this._initMethods(); this._observer = []; } notify(): void { for (let o of this._observer) { o.update(); } } private _initList(): void { var that = this; var operations = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']; for (let operation of operations) { this.list[operation] = function() { var res = Array.prototype[operation].apply(that.list, arguments); that.notify(); return res; } } } private _initMethods(): void { var that = this; var methods = ['filter', 'map']; for (let method of methods) { this[method] = (formatter: Function): ObserverList => { var observer = new ObserverList(that, formatter, method); this._observer.push(observer); return observer; } } } } export class ObserverList { public list: Array<any>; constructor(public observable: ObservableList, public formatter: Function, public method: string) { this.list = []; this.update(); } update(): void { var list = []; var master = this.observable.list; for (var i = 0, len = master.length; i < len; ++i) { if (this.method === 'filter') { if (this.formatter(master[i])) { list.push(master[i]); } } else if (this.method === 'map') { list.push(this.formatter(master[i])); } else { console.error('Illegal method ' + this.method + '.'); } } this.list = list; } }
Ovilia
source share