Technology moves fast! ⚡ Don't get left behind.🚶 Subscribe to our mailing list to keep up with latest and greatest in open source projects! 🏆


Subscribe to our mailing list

lell

Functional reactive state, no boilerplate necessary, built on Rx

Subscribe to updates I use lell


Statistics on lell

Number of watchers on Github 153
Number of open issues 0
Average time to close an issue 3 days
Main language JavaScript
Average time to merge a PR 4 days
Open pull requests 0+
Closed pull requests 0+
Last commit over 2 years ago
Repo Created over 3 years ago
Repo Last Updated over 1 year ago
Size 48 KB
Organization / Authorarkverse
Contributors1
Page Updated
Do you use lell? Leave a review!
View lell activity
View on github
Fresh, new opensource launches 🚀🚀🚀
Trendy new open source projects in your inbox! View examples

Subscribe to our mailing list

Evaluating lell for your project? Score Explanation
Commits Score (?)
Issues & PR Score (?)

lell - Build Status Latest Stable Version NPM Downloads Build Status Code Climate License

Make all your data observable without changing the way you do anything

Very small learning curve, enormous power.

Quick Use

Pop a model, subclassing Le is better but unnecessary

// model.js
import {Le, Ll} from 'lell'


var livingPerson = new Le({name:'z', power_level:9000})
// or
var livingPerson = new Person({name:'z',power_level:9000}) // if person extends Le


module.exports = {
  person:livingPerson
}

Read and subscribe!

// components/person.js
var model = require('./model.js')

class Person extends React.Component {
  constructor(props) {
    super(props)
    this.state = {person:model.person}
  }
  componentDidMount() {
    model.person.subscribe((person) => this.setState({person:person}))
  }
  tapIncreasePowerLevel() {
    model.person.power_level++
    // auto updates view
  }
  render() {
    var person = model.person
    return <div>
    <span>{person.name}</span> - {person.power_level}
    <button onClick={this.tapIncreasePowerLevel} />
    </div>
  }
}

Installation

Via npm:

npm install --save lell

Then require/import:

import {Le, Ll} from 'lell'
//or
var Le = require('lell').Le
var Ll = require('lell').Ll

Usage

Objects/Classes

Quick Living Entity

Just instantiate an Le with a payload

The only keys that cause events are the ones passed into the constructor

import {Le} from 'lell'

var aPerson = {name:'z',power_level:9000}

var aLivingPerson = new Le(aPerson)

aLivingPerson.subscribe((p) => console.log(p.power_level))

aLivingPerson.power_level++
// console output: 9001

An observable class

Extending an Le is only necessary if you can't init with all your properties or you just want convenience methods (like ajax requests) The living properties are only the ones we initialize with, so we have have to make sure our initial state holds all keys we wish to cause updates which is set in the _defaults method

import {Le} from 'lell'
import _ from 'lodash'

class Person extends Le {
  _defaults() {
    // having defaults makes these fields observable even if you haven't initialized with them
    return {name:'', power_level:0}
  }
  doSomeAsyncWork() {
    superagent
      .post('/increase_powerlevel')
      .send(this)
      .end((err, data) => {
        this.power_level++
    })
  }
}

var aLivingPerson = new Person()

aLivingPerson.subscribe((p) => console.log(p.name))

aLivingPerson.name = 'z'
// z

aLivingPerson.doSomeAsyncWork()
// z
Entity Mapping

Provide a map in your Le subclass so that an initial payload is initialized with Le's

class Person extends Le {
  _map() {
    return {friends:[Person], bestFriend:Person}
  }
}

var friendlyPerson = new Person({
  name:'z',
  bestFriend:{
    name:'s',
    power_level:9000
  },
  friends:[
    {
      name:'b',
      power_level:9001
    },
    {
      name:'n',
      power_level:9002
    }
  ]
})
// subscribe to bestFriend changes
friendlyPerson.bestFriend.subscribe((bf) => console.log(bf.power_level))
friendlyPerson.friends[0].subscribe((f) => console.log(f.power_level))
Some state information

Le's have state information you can use to help your web interfaces, ie, agnostic new/edit react views

var p = new Person()
console.log(p._state)
//new
p.power_level = 9000
console.log(p._state)
//new
console.log(p._updates)
// ["power_level"]
p._commit()
console.log(p._state)
// original
console.log(p._updates)
// []

var ep = new Person({name:'z', power_level:9000})
console.log(ep._state)
// original
ep.power_level++
console.log(ep._state)
// updated
ep.power_level--
console.log(ep._state)
// original
ep.power_level++
console.log(ep._state)
// updated
ep._commit()
console.log(ep._state)
// original
console.log(ep._updates)
// []
Rx.Observable available

The Rx observable subject is made available to you:

aLivingPerson.subject.pluck('power_level').subscribe((power_level) => console.log(power_level))

aLivingPerson.power_level = 9000
// 9000
Silent Updates

Update your instance without kicking off an update

aLivingPerson.subscribe((p) => console.log(p))

aLivingPerson.silentUpdate('power_level', 8999)
// no events

Lists

You can easily create living lists (Ll) that send notifications when the underlying array changes

You need to make changes through the array through the Lls methods addItems, removeItems, setItems

Quick list

We can make a simple living list

import {Ll} from 'lell'
//or
var Ll = require('lell').Ll

var abe = ...
var bush = ...
var people = [abe, bush]

var livingPeople = new Ll({people}) // this means {people: people}

livingPeople.subscribe((people) => console.log(people.length))

var kennedy = ...

livingPeople.addItems(kennedy)
// 3
livingPeople.removeItems([abe, bush])
// 1
livingPeople.setItems([abe, kennedy])
// 2
Sorted List

This is where Lls start getting good, you can supply a sort key/func to your Ll and your list will be sorted (borrows lodash _.sortBy)


var people = [{name:'z', power_level:9001}, {name:'y', power_level:9000}]
var livingPeople = new Ll({people, sort:'power_level'})

livingPeople.subscribe((people) => console.log(people[0].name))

livingPeople.addItems({name:'x', power_level:8999})
// x
Meant for Le's

Okay, that wasn't that cool, but Ll's are best when holding Le's

var livingPersonZ = new Person({name:'z',power_level:8999})
var livingPersonY = new Person({name:'y',power_level:9000})

var livingPeople = new Ll({
  people:[livingPersonZ, livingPersonY],
  sort:'power_level'
  })

console.log(livingPeople.people[1].name)
// y

livingPeople.subscribe((people) => console.log(people[1].name))

livingPersonZ.power_level = 9001
// z

Cool, huh? We have a reactive list

Subscribe each

You can listen to all of the items in a list, so when any Le in an Ll changes, you can be notified with that Le


livingPeople.subscribeEach((aPerson) => console.log(aPerson.power_level))

livingPersonZ.power_level++
// 9002

Rx.Observable availability

The observables are available to you, one for the list, subject, and one for the subscribeEach, itemChangeSubject

// note, you need to pluck people, because the root subject signals with the Le {people, sort}
livingPeople.subject.pluck('people').map(doSomething).subscribe(listen)

livingPeople.subject.pluck('power_level').average().subscribe(useAverage)
Subclassing is favorable

It really makes things convenient

import {Ll} from 'lell'
import _ from 'lodash'

var defaultState = {
  people:[personA, personB],
  sort:'power_level'
}

class People extends Ll {
  constructor(state) {
    state = state ? _.defaults(state, defaultState) : Object.assign({}, defaultState)
    super(state)
  }
}

var initialState = {people:[personA, personC, personX]}
var livingPeople = new People(people)

livingPeople.subscribe()

Future

  • Auto Hydrate/Serialize entire Le/Ll store between server/client
  • Le actions

License

The MIT License (MIT)

Copyright (c) 2016 ark

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the Software), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

lell list of languages used
More projects by arkverse View all
Other projects in JavaScript