UNPKG

@web-atoms/core-docs

Version:
210 lines 7.63 kB
(function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "./AtomBinder", "./ExpressionParser"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AtomWatcher = exports.ObjectProperty = void 0; const AtomBinder_1 = require("./AtomBinder"); const ExpressionParser_1 = require("./ExpressionParser"); class ObjectProperty { constructor(name) { this.name = name; } toString() { return this.name; } } exports.ObjectProperty = ObjectProperty; /** * * * @export * @class AtomWatcher * @implements {IDisposable} * @template T */ class AtomWatcher { /** * Creates an instance of AtomWatcher. * * let w = new AtomWatcher(this, x => x.data.fullName = `${x.data.firstName} ${x.data.lastName}`); * * You must dispose `w` in order to avoid memory leaks. * Above method will set fullName whenever, data or its firstName,lastName property is modified. * * AtomWatcher will assign null if any expression results in null in single property path. * * In order to avoid null, you can rewrite above expression as, * * let w = new AtomWatcher(this, * x => { * if(x.data.firstName && x.data.lastName){ * x.data.fullName = `${x.data.firstName} ${x.data.lastName}` * } * }); * * @param {T} target - Target on which watch will be set to observe given set of properties * @param {(PathList[] | ((x:T) => any))} path - Path is either lambda expression or array of * property path to watch, if path was lambda, it will be executed when any of * members will modify * @param {Function} onChanged - This function will be executed when any member in path is updated * @memberof AtomWatcher */ constructor(target, path, onChanged, source) { this.source = source; this.isExecuting = false; this.target = target; this.forValidation = true; if (path instanceof Function) { const f = path; path = ExpressionParser_1.parsePath(path); this.func = onChanged || f; this.funcText = f.toString(); } else { this.func = onChanged; } this.runEvaluate = () => { this.evaluate(); }; this.runEvaluate.watcher = this; this.path = path.map((x) => x.map((y) => new ObjectProperty(y))); if (!this.path.length) { // tslint:disable-next-line:no-debugger debugger; // tslint:disable-next-line:no-console console.warn("There is nothing to watch, do not use one way binding without any binding expression"); } } toString() { return this.func.toString(); } /** * This will dispose and unregister all watchers * * @memberof AtomWatcher */ dispose() { if (!this.path) { return; } for (const p of this.path) { for (const op of p) { if (op.watcher) { op.watcher.dispose(); op.watcher = null; op.target = null; } } } // tslint:disable-next-line:no-string-literal // this["disposedPath"] = this.path; this.func = null; // this.path.length = 0; this.path = null; this.source = null; } /** * Initialize the path targets * @param evaluate if true, evaluate entire watch expression and run onChange method */ init(evaluate) { if (evaluate) { this.evaluate(true); } else { for (const iterator of this.path) { this.evaluatePath(this.target, iterator); } } } evaluatePath(target, path) { // console.log(`\tevaluatePath: ${path.map(op=>op.name).join(", ")}`); let newTarget = null; for (const p of path) { if (this.source && p.name === "this") { target = this.source; continue; } newTarget = target[p.name]; if (!p.target) { if (p.watcher) { p.watcher.dispose(); } p.watcher = AtomBinder_1.AtomBinder.watch(target, p.name, this.runEvaluate); } else if (p.target !== target) { if (p.watcher) { p.watcher.dispose(); } p.watcher = AtomBinder_1.AtomBinder.watch(target, p.name, this.runEvaluate); } p.target = target; target = newTarget; if (newTarget === undefined || newTarget === null) { break; } } return newTarget; } /** * * * @param {boolean} [force] * @returns {*} * @memberof AtomWatcher */ evaluate(force) { if (!this.path) { // this watcher may have been disposed... // tslint:disable-next-line:no-console console.warn(`Watcher is not disposed properly, please watch for any memory leak`); return; } if (this.isExecuting) { return; } const disposeWatchers = []; this.isExecuting = true; try { const values = []; const logs = []; for (const p of this.path) { values.push(this.evaluatePath(this.target, p)); } // if (force === true) { // this.forValidation = false; // } // if (this.forValidation) { // const x: boolean = true; // if (values.find( (x1) => x1 ? true : false)) { // this.forValidation = false; // } else { // return; // } // } try { this.func.apply(this.target, values); } catch (e) { // tslint:disable-next-line:no-console console.warn(e); } } finally { this.isExecuting = false; for (const d of disposeWatchers) { d.dispose(); } } } } exports.AtomWatcher = AtomWatcher; }); //# sourceMappingURL=AtomWatcher.js.map