👯 SuperModel.js 👯
Harness the power of proxies!
- +: no depencies
- +: small size, SuperModel.min.js is ~4.5kb uncompressed
- -: only works in environments supporting Proxy
you can install from npm: npm install --save super-model-js
API
SuperModel( data = {}, emitter = SuperModel.emitter(), store = new Map() )
- create a new model.on(type, func)
,.once(type, func)
- model event listener.on[type](func)
,.once[type](func)
- event listener, type as function property.emit(type, ...values)
- emit an event with values.emit[type](...values)
- emit, event type as a function property.emitAsync(type, ...values)
- emit an event with values (non-blocking).del(key)
- delete model propertymodel(key, =val)
- shorthand function based property get/setmodel({...props})
- update properties with an objectmodel[prop]
- get/set model propertymodel.async[prop]
- get/set model property using promisesmodel.valid(key, =validator)
- make a property validate-able by adding a validator func/RegExpmodel.valid[prop]
- set - prop validator func/RegExp, get - run validator and get bool result.sync(obj, key, modelProperty = key)
- set and update a model property on an object.sync.stop(obj, key)
- stop syncing a model property on an object.store()
- Map containing all model properties.toJSON()
- Get all model.store properties as JSON.toJSONArray()
- Get all model.store properties as "[[key, val], ...]".has(key)
- checks whether model.store has a certain key.emitter()
- just the event emitting part of the model
Learn By Example
Async/Await Values
// view.js
const model = SuperModel()
feed.render(await model.async.news)
// news.js
model.news = await (await fetch('/latest')).json()
// psst... it also works if you simply assign a promise as is
model.news = (await fetch('/latest')).json()
Data Binding
<textarea id=txtarea>type something...</textarea>
<article id=txtdisplay></article>
const input = document.querySelector('#txtarea')
const output = document.querySelector('#txtdisplay')
const model = SuperModel()
model.sync.msg(input)
model.sync.msg(output, 'innerText')
Validate Properties
const model = SuperModel()
model.valid.username = /^[a-zA-Z0-9._]{3,55}$/g
model.username = '**Bad Username**'
model.valid.username // -> false
model.valid('username') // -> false
model.ui = {...someUIcomponent}
model.valid.ui = ui => !ui.hidden && ui.userlist.includes(model.username)
// or
model.valid('ui', ui => !ui.hidden && ui.userlist.includes(model.username))
model.valid.ui // -> bool
// listen for validation event
model.on('validate:username', isValid => {
// ...
})
// or
model.on.validate((propName, isValid) => {
if (propName === 'username') {
// ...
}
})
Emit Events
more or less node.js style events
const model = SuperModel()
model.on.myevent((...values) => {
// ... do something
console.log(...values)
})
model.emit.myevent('new', 'values')
// or
model.emit('myevent', 'newer', 'values')
stop event listeners
const model = SuperModel()
const off = model.on.happening(() => {})
off() // no longer happening
Mutations
internally all values are stored in a map
const model = SuperModel()
model.store // -> Map{"key":"value"}
// set
model('key', 'value')
model({ key: 'value' })
model.key = 'value'
// get
model('key') // -> val
model.key // -> val
model.async.key // -> promise.then(val => {...})
// delete
model.del('key')
delete model.key
listening to mutation events
there are 3 mutation types set, get, del
model.on('type:key', val => {})
model.on('type', (key, val) => {})
const model = SuperModel()
model.on('set:existentialism', val => {
// render to dom or something...
})
// or
model.on.set((key, val) => {
if (key === 'existentialism') {
// ...
}
})
model.existentialism = 'What ever matters to you.'
other things
sync model values with other objects
.sync(obj, key, modelProperty = key)
,
.sync.stop(obj, key)
const model = SuperModel()
model({ PhilosophyOfTheDay: 'pragmatism' })
const PHODelement = document.querySelector('#PHOD')
// this keeps obj[key] updated with model[prop]
model.sync(PHODelement, 'textContent', 'PhilosophyOfTheDay')
if (nolongerToday) {
// this will update the element's text
model.PhilosophyOfTheDay = 'nominalism'
} else if (fedUpWithPositivism) {
model.PhilosophyOfTheDay = 'critical-realism'
}
// stop syncing
model.sync.stop(PHODelement, 'textContent')
.emitAsync
is the same as .emit
it's just less slightly blocking by running the event loop
and each event listener in a setTimeout(ln, 0)
const model = SuperModel()
model.emitAsync('evtType', ...['values'])