mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] reactivity: add missing support for forEach method
This commit is contained in:
committed by
Géry Debongnie
parent
53ab54b1ec
commit
0625b5883a
@@ -308,6 +308,28 @@ function makeIteratorObserver(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Creates a forEach function that will delegate to forEach on the underlying
|
||||||
|
* collection while observing key changes, and keys as they're iterated over,
|
||||||
|
* and making the passed keys/values reactive.
|
||||||
|
*
|
||||||
|
* @param target @see reactive
|
||||||
|
* @param callback @see reactive
|
||||||
|
*/
|
||||||
|
function makeForEachObserver(target: any, callback: Callback) {
|
||||||
|
return function forEach(forEachCb: (val: any, key: any, target: any) => void, thisArg: any) {
|
||||||
|
observeTargetKey(target, KEYCHANGES, callback);
|
||||||
|
target.forEach(function (val: any, key: any, targetObj: any) {
|
||||||
|
observeTargetKey(target, key, callback);
|
||||||
|
forEachCb.call(
|
||||||
|
thisArg,
|
||||||
|
possiblyReactive(val, callback),
|
||||||
|
possiblyReactive(key, callback),
|
||||||
|
possiblyReactive(targetObj, callback)
|
||||||
|
);
|
||||||
|
}, thisArg);
|
||||||
|
};
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Creates a function that will delegate to an underlying method, and check if
|
* Creates a function that will delegate to an underlying method, and check if
|
||||||
* that method has modified the presence or value of a key, and notify the
|
* that method has modified the presence or value of a key, and notify the
|
||||||
@@ -370,6 +392,7 @@ const rawTypeToFuncHandlers = {
|
|||||||
values: makeIteratorObserver("values", target, callback),
|
values: makeIteratorObserver("values", target, callback),
|
||||||
entries: makeIteratorObserver("entries", target, callback),
|
entries: makeIteratorObserver("entries", target, callback),
|
||||||
[Symbol.iterator]: makeIteratorObserver(Symbol.iterator, target, callback),
|
[Symbol.iterator]: makeIteratorObserver(Symbol.iterator, target, callback),
|
||||||
|
forEach: makeForEachObserver(target, callback),
|
||||||
clear: makeClearNotifier(target),
|
clear: makeClearNotifier(target),
|
||||||
get size() {
|
get size() {
|
||||||
observeTargetKey(target, KEYCHANGES, callback);
|
observeTargetKey(target, KEYCHANGES, callback);
|
||||||
@@ -385,6 +408,7 @@ const rawTypeToFuncHandlers = {
|
|||||||
values: makeIteratorObserver("values", target, callback),
|
values: makeIteratorObserver("values", target, callback),
|
||||||
entries: makeIteratorObserver("entries", target, callback),
|
entries: makeIteratorObserver("entries", target, callback),
|
||||||
[Symbol.iterator]: makeIteratorObserver(Symbol.iterator, target, callback),
|
[Symbol.iterator]: makeIteratorObserver(Symbol.iterator, target, callback),
|
||||||
|
forEach: makeForEachObserver(target, callback),
|
||||||
clear: makeClearNotifier(target),
|
clear: makeClearNotifier(target),
|
||||||
get size() {
|
get size() {
|
||||||
observeTargetKey(target, KEYCHANGES, callback);
|
observeTargetKey(target, KEYCHANGES, callback);
|
||||||
|
|||||||
@@ -1245,6 +1245,33 @@ describe("Collections", () => {
|
|||||||
reactiveObj.a = 1; // setting same value again shouldn't notify
|
reactiveObj.a = 1; // setting same value again shouldn't notify
|
||||||
expect(observer).toHaveBeenCalledTimes(1);
|
expect(observer).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("iterating with forEach returns reactives", async () => {
|
||||||
|
const keyObj = { a: 2 };
|
||||||
|
const thisArg = {};
|
||||||
|
const observer = jest.fn();
|
||||||
|
const state = reactive(new Set([keyObj]), observer);
|
||||||
|
let reactiveKeyObj: any, reactiveValObj: any, thisObj: any, mapObj: any;
|
||||||
|
state.forEach(function (this: any, val, key, map) {
|
||||||
|
[reactiveValObj, reactiveKeyObj, mapObj, thisObj] = [val, key, map, this];
|
||||||
|
}, thisArg);
|
||||||
|
expect(reactiveKeyObj).not.toBe(keyObj);
|
||||||
|
expect(reactiveValObj).not.toBe(keyObj);
|
||||||
|
expect(mapObj).toBe(state); // third argument should be the reactive
|
||||||
|
expect(thisObj).toBe(thisArg); // thisArg should not be made reactive
|
||||||
|
expect(toRaw(reactiveKeyObj as any)).toBe(keyObj);
|
||||||
|
expect(toRaw(reactiveValObj as any)).toBe(keyObj);
|
||||||
|
expect(reactiveKeyObj).toBe(reactiveValObj); // reactiveKeyObj and reactiveValObj should be the same object
|
||||||
|
reactiveKeyObj!.a = 0;
|
||||||
|
reactiveValObj!.a = 0;
|
||||||
|
expect(observer).toHaveBeenCalledTimes(0);
|
||||||
|
reactiveKeyObj!.a; // observe key "a" in key sub-reactive;
|
||||||
|
reactiveKeyObj!.a = 1;
|
||||||
|
expect(observer).toHaveBeenCalledTimes(1);
|
||||||
|
reactiveKeyObj!.a = 1; // setting same value again shouldn't notify
|
||||||
|
reactiveValObj!.a = 1;
|
||||||
|
expect(observer).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("WeakSet", () => {
|
describe("WeakSet", () => {
|
||||||
@@ -1467,6 +1494,36 @@ describe("Collections", () => {
|
|||||||
reactiveValObj.a = 1;
|
reactiveValObj.a = 1;
|
||||||
expect(observer).toHaveBeenCalledTimes(2);
|
expect(observer).toHaveBeenCalledTimes(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("iterating with forEach returns reactives", async () => {
|
||||||
|
const keyObj = { a: 2 };
|
||||||
|
const valObj = { a: 2 };
|
||||||
|
const thisArg = {};
|
||||||
|
const observer = jest.fn();
|
||||||
|
const state = reactive(new Map([[keyObj, valObj]]), observer);
|
||||||
|
let reactiveKeyObj: any, reactiveValObj: any, thisObj: any, mapObj: any;
|
||||||
|
state.forEach(function (this: any, val, key, map) {
|
||||||
|
[reactiveValObj, reactiveKeyObj, mapObj, thisObj] = [val, key, map, this];
|
||||||
|
}, thisArg);
|
||||||
|
expect(reactiveKeyObj).not.toBe(keyObj);
|
||||||
|
expect(reactiveValObj).not.toBe(valObj);
|
||||||
|
expect(mapObj).toBe(state); // third argument should be the reactive
|
||||||
|
expect(thisObj).toBe(thisArg); // thisArg should not be made reactive
|
||||||
|
expect(toRaw(reactiveKeyObj as any)).toBe(keyObj);
|
||||||
|
expect(toRaw(reactiveValObj as any)).toBe(valObj);
|
||||||
|
reactiveKeyObj!.a = 0;
|
||||||
|
reactiveValObj!.a = 0;
|
||||||
|
expect(observer).toHaveBeenCalledTimes(0);
|
||||||
|
reactiveKeyObj!.a; // observe key "a" in key sub-reactive;
|
||||||
|
reactiveKeyObj!.a = 1;
|
||||||
|
expect(observer).toHaveBeenCalledTimes(1);
|
||||||
|
reactiveValObj!.a; // observe key "a" in val sub-reactive;
|
||||||
|
reactiveValObj!.a = 1;
|
||||||
|
expect(observer).toHaveBeenCalledTimes(2);
|
||||||
|
reactiveKeyObj!.a = 1; // setting same value again shouldn't notify
|
||||||
|
reactiveValObj!.a = 1;
|
||||||
|
expect(observer).toHaveBeenCalledTimes(2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("WeakMap", () => {
|
describe("WeakMap", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user