Allow silent changes to observed property
This commit is contained in:
parent
ae6b90bee3
commit
e634e3a01d
@ -30,6 +30,9 @@ export default class uObserve {
|
|||||||
* @param {ObserveCallback=} p2
|
* @param {ObserveCallback=} p2
|
||||||
*/
|
*/
|
||||||
static observe(obj, p1, p2) {
|
static observe(obj, p1, p2) {
|
||||||
|
if (typeof obj !== 'object' || obj === null) {
|
||||||
|
throw new Error('Invalid argument: invalid object');
|
||||||
|
}
|
||||||
if (typeof p2 === 'function') {
|
if (typeof p2 === 'function') {
|
||||||
this.observeProperty(obj, p1, p2);
|
this.observeProperty(obj, p1, p2);
|
||||||
} else if (typeof p1 === 'function') {
|
} else if (typeof p1 === 'function') {
|
||||||
@ -62,6 +65,31 @@ export default class uObserve {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static isObserved(obj, property) {
|
||||||
|
if (typeof obj !== 'object' || obj === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return obj.hasOwnProperty(property) && obj.hasOwnProperty('_values') &&
|
||||||
|
obj._values.hasOwnProperty(property) && !!Object.getOwnPropertyDescriptor(obj, property)['set'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set observed property value without notifying observers
|
||||||
|
* @param {Object} obj
|
||||||
|
* @param {string} property
|
||||||
|
* @param {*} value
|
||||||
|
*/
|
||||||
|
static setSilently(obj, property, value) {
|
||||||
|
if (!obj.hasOwnProperty(property)) {
|
||||||
|
throw new Error(`Invalid argument: object does not have property "${property}"`);
|
||||||
|
}
|
||||||
|
if (this.isObserved(obj, property)) {
|
||||||
|
obj._values[property] = value;
|
||||||
|
} else {
|
||||||
|
obj[property] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observe object's property. On change call observer
|
* Observe object's property. On change call observer
|
||||||
* @param {Object} obj
|
* @param {Object} obj
|
||||||
@ -69,6 +97,9 @@ export default class uObserve {
|
|||||||
* @param {ObserveCallback} observer
|
* @param {ObserveCallback} observer
|
||||||
*/
|
*/
|
||||||
static observeProperty(obj, property, observer) {
|
static observeProperty(obj, property, observer) {
|
||||||
|
if (!obj.hasOwnProperty(property)) {
|
||||||
|
throw new Error(`Invalid argument: object does not have property "${property}"`);
|
||||||
|
}
|
||||||
this.addObserver(obj, observer, property);
|
this.addObserver(obj, observer, property);
|
||||||
if (!obj.hasOwnProperty('_values')) {
|
if (!obj.hasOwnProperty('_values')) {
|
||||||
Object.defineProperty(obj, '_values', { enumerable: false, configurable: false, value: {} });
|
Object.defineProperty(obj, '_values', { enumerable: false, configurable: false, value: {} });
|
||||||
|
@ -334,6 +334,65 @@ describe('Observe tests', () => {
|
|||||||
expect(resultValue2).toEqual(undefined);// eslint-disable-line no-undefined
|
expect(resultValue2).toEqual(undefined);// eslint-disable-line no-undefined
|
||||||
expect(array).toEqual([ 1, 2, 3 ]);
|
expect(array).toEqual([ 1, 2, 3 ]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should throw error when observing non-existing property', () => {
|
||||||
|
// given
|
||||||
|
const nonExisting = '___non-existing___';
|
||||||
|
|
||||||
|
expect(object.hasOwnProperty(nonExisting)).toBe(false);
|
||||||
|
// then
|
||||||
|
expect(() => uObserve.observe(object, nonExisting, (value) => {
|
||||||
|
result = true;
|
||||||
|
resultValue = value;
|
||||||
|
})).toThrow();
|
||||||
|
|
||||||
|
expect(object.hasOwnProperty(nonExisting)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw error when observing non-object', () => {
|
||||||
|
// given
|
||||||
|
const nonExisting = '___non-existing___';
|
||||||
|
// then
|
||||||
|
expect(() => uObserve.observe(nonExisting, (value) => {
|
||||||
|
result = true;
|
||||||
|
resultValue = value;
|
||||||
|
})).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw error when observing null object', () => {
|
||||||
|
// given
|
||||||
|
const nullObject = null;
|
||||||
|
// then
|
||||||
|
expect(() => uObserve.observe(nullObject, (value) => {
|
||||||
|
result = true;
|
||||||
|
resultValue = value;
|
||||||
|
})).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not notify observers when observed property is silently changed', () => {
|
||||||
|
// given
|
||||||
|
uObserve.observe(object, 'observed', (value) => {
|
||||||
|
result = true;
|
||||||
|
resultValue = value;
|
||||||
|
});
|
||||||
|
// when
|
||||||
|
expect(result).toBe(false);
|
||||||
|
uObserve.setSilently(object, 'observed', 2);
|
||||||
|
// then
|
||||||
|
expect(result).toBe(false);
|
||||||
|
// eslint-disable-next-line no-undefined
|
||||||
|
expect(resultValue).toBe(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true if property is observed', () => {
|
||||||
|
// when
|
||||||
|
uObserve.observe(object, 'observed', (value) => {
|
||||||
|
result = true;
|
||||||
|
resultValue = value;
|
||||||
|
});
|
||||||
|
// then
|
||||||
|
expect(uObserve.isObserved(object, 'observed')).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when notify is called directly', () => {
|
describe('when notify is called directly', () => {
|
||||||
@ -351,5 +410,6 @@ describe('Observe tests', () => {
|
|||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
expect(result2).toBe(true);
|
expect(result2).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user