Skip to content

futurist/edata

Repository files navigation

EDATA (Enhanced DATA)

edata is the nested observable reactive EventEmitter with .value getter/setter, lodash style path, and keep Observer Pattern in mind.

It roughly referenced Object.observe API, but instead using getter/setter to wrap object, lightweight than Proxy.

Build Status NPM Version

Install

NPM

npm install --save edata
import edata from 'edata'

Usage

- Quick Start

Below can give you a quick idea of edata:

var root = edata({a: {b: {c: {}}}}) // plain_object ---> edata

Complete example:

import edata from 'edata' const root = edata({ age: 20, firstName: 'Hello', lastName: 'World', address: { city: 'Earth' } }) const callback = ({type, path}) => console.log(`--> ${type}: ${path}`) root.watch(callback) root.set('address.city', 'Moon') // LOG: --> update: ['address', 'city'] root.get('address.city').value // Moon

Plain object wrapped into edata:

edata = new EventEmitter(object)

so use edata.on can watch changes, use edata.value(getter/setter) to get nested edata.

root.value.firstName.value // get -> firstName root.value.firstName.value = 'name' // set -> firstName root.value.address.value.city.on('change', callback) // watch on 'change'

Can also use lodash style:

root.get('firstName').value // get: firstName root.set('firstName', 'name') // set: firstName root.get('address.city').on('change', ...) // watch change

Proxy usage:

use .proxy() to shorten the path:

const data = root.proxy() data.address.city // Moon data.__edata__ // get back the `root` edata

- Watch changes

Any edata can watch data changes inside(any level):

const onDataChange = ({data, type, path})=>{ console.log('value mutated:', path, type, data.unwrap()) } const unwatch = root.watch('change', onDataChange) root.set('address.city', 'Mars') // [LOG] data mutated: [ 'address', 'city' ] add Mars unwatch() // stop watch root.get('address.city').value = 'Earth' // nothing outout

Watch single data change event:

root.get('firstName').on('change', ({path, type, data})=>{ console.log(path, type, 'to: ' + data) }) root.set('firstName', 'Hi') //[LOG] firstName update to: Hi

Note: edata.on('change', callback) has shortcut: edata.map(callback)

- Define Data Relations

You can define data relations using setComputed, as below:

const root = edata({ firstName: 'Hello', lastName: 'World' }) root.setComputed( 'fullName', ['firstName', 'lastName'], ([firstName, lastName]) => firstName + ' ' + lastName ) assert.equal(root.unwrap('fullName'), 'Hello World') root.set('firstName', 'Green') assert.equal(root.unwrap('fullName'), 'Green World')

- Flat data

Since the edata objects nested as EventEmitter, you can flat this structure into plain object using edata.unwrap():

root.unwrap() // flat root: {age: 20, firstName: 'Hello', lastName: 'World', address: {city: 'Earth'}} root.unwrap('address') // flat address: {city: 'Earth'} root.unset('address') // delete address root.unwrap() // {age: 20, firstName: 'Hello', lastName: 'World'}

Also exist edata.toJSON(), so the JSON.stringify(edata) just like

JSON.stringify(edata.unwrap({json:true}))

- Use in React

The pros is you can use edata.set() instead of this.setState:

import edata from 'edata' const root = edata({user: {name: 'earth'}}) class App extends React.Component { constructor(props){ super(props) const {model} = this.props this.state = model.unwrap() // state: {name: 'earth'} model.watch(()=>{ this.setState(model.unwrap()) }) } render(){ const {model} = this.props const name = model.unwrap('name') return <div> <h3>Name: {name}</h3> <input value={name} onChange={e=>{model.set('name', e.target.value)}} /> </div> } } ReactDOM.render(<App edata={root.cut('user')} />, app)

You can play with the demo here

API

See API Document

About

Turn javascript data into observable reactive EventEmitter with value getter/setter, lodash style path, and keep Event Sourcing in mind.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors