Skip to content

Manage your app's state like never before, harness the power of the proxy! πŸ‘―

License

Notifications You must be signed in to change notification settings

SaulDoesCode/SuperModel.js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 Cannot retrieve latest commit at this time.

History

36 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

πŸ‘― SuperModel.js πŸ‘―

Harness the power of proxies!

JavaScript Style Guide

  • +: 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 property
  • model(key, =val)- shorthand function based property get/set
  • model({...props})- update properties with an object
  • model[prop]- get/set model property
  • model.async[prop]- get/set model property using promises
  • model.valid(key, =validator)- make a property validate-able by adding a validator func/RegExp
  • model.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'])