map operator for observable lists

This commit is contained in:
Bruno Windels 2019-07-29 19:17:55 +02:00
parent 0b5c2f9273
commit 6f650d19b1
2 changed files with 116 additions and 0 deletions

View File

@ -5,6 +5,7 @@ import BaseObservableMap from "./map/BaseObservableMap.js";
// re-export "root" (of chain) collections // re-export "root" (of chain) collections
export { default as ObservableArray } from "./list/ObservableArray.js"; export { default as ObservableArray } from "./list/ObservableArray.js";
export { default as SortedArray } from "./list/SortedArray.js"; export { default as SortedArray } from "./list/SortedArray.js";
export { default as MappedList } from "./list/MappedList.js";
export { default as ObservableMap } from "./map/ObservableMap.js"; export { default as ObservableMap } from "./map/ObservableMap.js";
// avoid circular dependency between these classes // avoid circular dependency between these classes

View File

@ -0,0 +1,115 @@
import BaseObservableList from "./BaseObservableList.js";
export default class MappedList extends BaseObservableList {
constructor(sourceList, mapper, updater) {
super();
this._sourceList = sourceList;
this._mapper = mapper;
this._updater = updater;
this._sourceUnsubscribe = null;
this._mappedValues = null;
}
onSubscribeFirst() {
this._sourceUnsubscribe = this._sourceList.subscribe(this);
this._mappedValues = [];
for (const item of this._sourceList) {
this._mappedValues.push(this._mapper(item));
}
}
onReset() {
this._mappedValues = [];
this.emitReset();
}
onAdd(index, value) {
const mappedValue = this._mapper(value);
this._mappedValues.splice(index, 0, mappedValue);
this.emitAdd(index, mappedValue);
}
onUpdate(index, value, params) {
const mappedValue = this._mappedValues[index];
if (this._updater) {
this._updater(mappedValue, value);
}
this.emitUpdate(index, mappedValue, params);
}
onRemove(index) {
const mappedValue = this._mappedValues[index];
this._mappedValues.splice(index, 1);
this.emitRemove(index, mappedValue);
}
onMove(fromIdx, toIdx) {
const mappedValue = this._mappedValues[fromIdx];
this._mappedValues.splice(fromIdx, 1);
this._mappedValues.splice(toIdx, 0, mappedValue);
this.emitMove(fromIdx, toIdx, mappedValue);
}
onUnsubscribeLast() {
this._sourceUnsubscribe();
}
get length() {
return this._mappedValues.length;
}
[Symbol.iterator]() {
return this._mappedValues.values();
}
}
export async function tests() {
class MockList extends BaseObservableList {
get length() {
return 0;
}
[Symbol.iterator]() {
return [].values();
}
}
return {
test_add(assert) {
const source = new MockList();
const mapped = new MappedList(source, n => {return {n: n*n};});
let fired = false;
const unsubscribe = mapped.subscribe({
onAdd(idx, value) {
fired = true;
assert.equal(idx, 0);
assert.equal(value.n, 36);
}
});
source.emitAdd(0, 6);
assert(fired);
unsubscribe();
},
test_update(assert) {
const source = new MockList();
const mapped = new MappedList(
source,
n => {return {n: n*n};},
(o, n) => o.m = n*n
);
let fired = false;
const unsubscribe = mapped.subscribe({
onAdd() {},
onUpdate(idx, value) {
fired = true;
assert.equal(idx, 0);
assert.equal(value.n, 36);
assert.equal(value.m, 49);
}
});
source.emitAdd(0, 6);
source.emitUpdate(0, 7);
assert(fired);
unsubscribe();
}
};
}