better isRx will determine if any parent to root is reactive
parent
543cad8bac
commit
4b76b80f07
128
src/rx-class.js
128
src/rx-class.js
|
@ -1,3 +1,4 @@
|
|||
// import methods from './public-methods.js'
|
||||
// native modules
|
||||
import { EventEmitter } from 'events'
|
||||
// reactive modules
|
||||
|
@ -5,7 +6,7 @@ import { BehaviorSubject, from } from 'rxjs'
|
|||
import { distinctUntilChanged, skip } from 'rxjs/operators'
|
||||
// uci modules
|
||||
import { check } from '@uci-utils/type'
|
||||
import { get, set, del, getKeys, pathToString } from '@uci-utils/obj-nested-prop'
|
||||
import { get, set, del, walkPath, getKeys, pathToString } from '@uci-utils/obj-nested-prop'
|
||||
import { logger } from '@uci-utils/logger'
|
||||
// supporting
|
||||
import equal from 'deep-equal'
|
||||
|
@ -17,7 +18,6 @@ const log = logger({ file: '/src/rx-class.js', package: '@uci-utils/rx-class', c
|
|||
class RxClass extends EventEmitter {
|
||||
// private fields
|
||||
#rx
|
||||
#rxM
|
||||
|
||||
constructor (opts = {}) {
|
||||
super(opts)
|
||||
|
@ -32,8 +32,9 @@ class RxClass extends EventEmitter {
|
|||
hook: rxopts.hook, // function called when setting
|
||||
namespace: rxopts.namespace || 'rx', // TODO namespace to added to all public rx methods
|
||||
operators: new Map(), // TODO added to all rx pipes, in order
|
||||
skip: rxopts.skip == null ? 0 : rxopts.skip
|
||||
skip: rxopts.skip == null ? 1 : rxopts.skip
|
||||
}
|
||||
this.isRx.bind(this)
|
||||
}
|
||||
|
||||
get (path) {
|
||||
|
@ -51,25 +52,29 @@ class RxClass extends EventEmitter {
|
|||
}
|
||||
|
||||
set (path, value, opts = {}) {
|
||||
// console.log(path,value,opts,!this.isRx(path))
|
||||
if (!opts.noRx && !this.isRx(path)) {
|
||||
opts = Object.assign(check.isPlainObject(value) ? { values: value, traverse: true } : { value: value }, opts)
|
||||
// console.log('set opts', opts)
|
||||
console.log('set:', path, value, opts, !this.isRx(path))
|
||||
if (!opts.noRx && !this.isRx(path)) { // travsere
|
||||
opts = Object.assign(
|
||||
(check.isPlainObject(value) && opts.traverse !== false)
|
||||
? { values: value, traverse: true }
|
||||
: { value: value }
|
||||
, opts)
|
||||
console.log('adding rx from set', opts)
|
||||
this.rxAdd(path, opts)
|
||||
} else {
|
||||
const curValue = this.#get(path)
|
||||
if (!equal(curValue, value) && value !== undefined) {
|
||||
// console.log('in set', path,value)
|
||||
console.log('setting already reactive value', path, value)
|
||||
this.#set(path, value)
|
||||
// console.log('value that was set',this.#get(path))
|
||||
console.log('value that was set', this.#get(path))
|
||||
}
|
||||
return this.#get(path)
|
||||
}
|
||||
}
|
||||
|
||||
// getRaw () {
|
||||
// return get(this, [this.#rx.namespace, ...arguments])
|
||||
// }
|
||||
getRaw () {
|
||||
return get(this, [this.#rx.namespace, ...arguments])
|
||||
}
|
||||
|
||||
// if property exists it moves value to #rx.props and creates getter and setter and behavior subject
|
||||
rxAdd (path, opts = {}) {
|
||||
|
@ -78,23 +83,24 @@ class RxClass extends EventEmitter {
|
|||
const self = this
|
||||
// console.log('object to traverse', obj)
|
||||
traverse(obj).map(function () {
|
||||
// console.log('traversing', this)
|
||||
if (this.isLeaf) {
|
||||
const lpath = this.path
|
||||
lpath.unshift(path)
|
||||
// console.log(`#{!opts.values ? 'existing':'new'} leaf on path '#{lpath}' with value: #{this.node}`)
|
||||
// console.log('#{!opts.values ? \'existing\':\'new\'} leaf on path \'#{lpath}\' with value: #{this.node}')
|
||||
self.rxAdd(lpath, { value: this.node })
|
||||
}
|
||||
return true
|
||||
}
|
||||
)
|
||||
return true
|
||||
} // end traverse
|
||||
if (this.isRx(path) && !opts.force) return true
|
||||
const value = this.#get(path) // current value
|
||||
if (value === undefined) {
|
||||
// console.log ('no current property or value for',path,'creating temporary null')
|
||||
// console.log('no current property or value for', path, 'creating temporary null')
|
||||
this.#set(path, null)
|
||||
}
|
||||
if (this.isRx(path) && !opts.force) return true
|
||||
console.log(path, 'making reactive')
|
||||
const { parent, name } = this.#rxGetObj(path, '__parent__')
|
||||
log.debug({
|
||||
class: 'RxClass',
|
||||
|
@ -149,6 +155,7 @@ class RxClass extends EventEmitter {
|
|||
if (check.isFunction(rx.hook)) rx.hook.call(self, value) // property hook
|
||||
}
|
||||
})
|
||||
// console.log('rxadd done', path, opts, this.#get(['#rx.props', path]))
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -183,7 +190,6 @@ class RxClass extends EventEmitter {
|
|||
lpath.unshift(path)
|
||||
if (self.isRx(lpath)) self.rxRemove(lpath, { confirm: true })
|
||||
}
|
||||
return true
|
||||
})
|
||||
// all done removing the leaves so remove branch
|
||||
this.#del(['#rx.props', path], true)
|
||||
|
@ -244,30 +250,74 @@ class RxClass extends EventEmitter {
|
|||
return false
|
||||
}
|
||||
|
||||
// // takes several formats for a path to an objects property and return only the . string
|
||||
// formatObjPath (path) {
|
||||
// if (path == null) return path
|
||||
// if (Array.isArray(path)) {
|
||||
// path = path.filter(Boolean).join('.') // Boolean filter strips empty strings or null/undefined
|
||||
// }
|
||||
// path = path.replace(/\/:,/g, '.') // replaces /:, with .
|
||||
// return path
|
||||
// }
|
||||
|
||||
// checks for getter and the corresponding rx object
|
||||
isRx (path) {
|
||||
// console.log(path)
|
||||
if (this.#get(path) === undefined) return false
|
||||
const { parent, name, parentPath } = this.#rxGetObj(path, '__parent__')
|
||||
// console.log(parent, name, parentPath)
|
||||
const rxparent = this.#get(['#rx.props', parentPath]) || {}
|
||||
const rx = rxparent[name]
|
||||
// console.log(path, 'rxparent,rx', !!parent, !!name, !!rxparent, !!rx)
|
||||
if (!rx) return false
|
||||
// console.log(Object.getOwnPropertyDescriptor(parent, name).get)
|
||||
return !!Object.getOwnPropertyDescriptor(parent, name).get
|
||||
isGetSet (path) {
|
||||
const keys = getKeys(path)
|
||||
const prop = keys.pop()
|
||||
const parent = this.#get(keys)
|
||||
// console.log('isgetset', path, keys, prop, 'parent?', !!parent)
|
||||
if (parent && prop) {
|
||||
return !!(Object.getOwnPropertyDescriptor(parent, prop) || {}).get &&
|
||||
!!(Object.getOwnPropertyDescriptor(parent, prop) || {}).set
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// is already reactive, checks for setter/getter and the corresponding rx object
|
||||
isRx (path) {
|
||||
// console.log('in isRX', path)
|
||||
const keys = getKeys(path)
|
||||
const cnt = keys.length
|
||||
for (let index = 0; index < cnt; index++) {
|
||||
// console.log('testing rx', index, cnt, keys, !!this.#get(keys), !!this.isGetSet(keys), !!this.#get(['#rx.props', keys]))
|
||||
if (this.#get(keys) === undefined) return false
|
||||
if (this.isGetSet(keys) && this.#get(['#rx.props', keys])) return true
|
||||
keys.pop()
|
||||
}
|
||||
return false
|
||||
// // console.log('in rx every', lpath)
|
||||
// // if (this.#get(['#rx.props', ...lpath]) === undefined) {
|
||||
// // return false
|
||||
// // }
|
||||
// //
|
||||
// console.log(parent, name, parentPath)
|
||||
// const rxparent = this.#get(['#rx.props', parentPath]) || {}
|
||||
// const rx = rxparent[name]
|
||||
// console.log(path, 'rxparent,rx', !!parent, !!name, !!rxparent, !!rx)
|
||||
// if (!rx) return true
|
||||
// else {
|
||||
// console.log(Object.getOwnPropertyDescriptor(parent, name).get)
|
||||
// isRx = !!Object.getOwnPropertyDescriptor(parent, name).get
|
||||
// return false
|
||||
// }
|
||||
// })
|
||||
// return isRx
|
||||
}
|
||||
|
||||
// isRx(path) {
|
||||
// // console.log(path)
|
||||
// let isRx = false
|
||||
// const lpath = []
|
||||
// getKeys(path).every(key => {
|
||||
// lpath.push(key)
|
||||
// console.log('in rx every', lpath, this.#get(lpath))
|
||||
// if (this.#get(lpath) === undefined) {
|
||||
// return false
|
||||
// }
|
||||
// // const { parent, name, parentPath } = this.#rxGetObj(lpath, '__parent__')
|
||||
// // console.log(parent, name, parentPath)
|
||||
// const rxparent = this.#get(['#rx.props', parentPath]) || {}
|
||||
// const rx = rxparent[name]
|
||||
// console.log(path, 'rxparent,rx', !!parent, !!name, !!rxparent, !!rx)
|
||||
// if (!rx) return true
|
||||
// else {
|
||||
// console.log(Object.getOwnPropertyDescriptor(parent, name).get)
|
||||
// isRx = !!Object.getOwnPropertyDescriptor(parent, name).get
|
||||
// return false
|
||||
// }
|
||||
// })
|
||||
// return isRx
|
||||
// }
|
||||
|
||||
// PRIVATE METHODS
|
||||
|
||||
// pass '__parent__' when getting objects for creating reactive prop
|
||||
|
|
Loading…
Reference in New Issue