muxjs

Modeling app states with muxjs.

Usage no npm install needed!

<script type="module">
  import muxjs from 'https://cdn.skypack.dev/muxjs';
</script>

README

logo"> Muxjs

build Coverage Status npm version

Using Muxjs is easy to track the app state. What's state and it's tansition? When look back your codes, often find some logic are described as below:

if this condition and this other condition are met, then this value should be 'x'.

Here, vars of condition are state, and condition is transition, so 'x' is the transposition's result. Muxjs give the way to subscribe vars's changs and transition's result 'x''s changes.

Let's look at the diagram of an example case of an stateful application:

Case Diagram

Left of diagram is a view-controller with 5 state (circle) and 3 transition (rhombus).
Right of disgram is an UI Page with 4 parts, each part depend on one state or transition. If we can subscribe all changes of state and transition, so we can bind specified DOM opertion when state/transition change, finally it implement the data to DOM binding , event can do more stuff for a completed MVVM framework such as Zect. It's usefull, right?

Installation

browser:

<script src="dist/mux.js"></script>

node.js:

npm install muxjs --save

Examples:

API Reference

Wiki

Global API

Mux(options)

:bookmark: API Reference Navigation

It is a constructor function that allows you to create Mux instance.options see: Instance Options.

var author = new Mux({
    props: {
        name: 'firstName lastName'
    },
    computed: {
        firstName: {
            deps: ['name'],
            fn: function () {
                return this.name.split(' ')[0]
            }
        }
    }
})
assert.equal(author.firstName, 'firstName')
Mux.extend([options])
  • Return: Function Class

:bookmark: API Reference Navigation

Create a subclass of the base Mux constructor. options see: Instance Options.

Class can instance with param propsObj which will set values to those observered properties of the instance.

var Person = Mux.extend({
    props: {
        profession: 'programer',
        name: ''
    }
})
var author = new Person({
    name: 'switer'
})
assert.equal(author.profession, 'programer')
assert.equal(author.name, 'switer')
Mux.config([conf])

:bookmark: API Reference Navigation

Global configure. Currently supported configurations: * warn Boolean if value is false, don't show any warning log. Default is true

Mux.config({
    warn: false // no warning log
})
Mux.emitter([context])
  • Params:
    • context Object binding "this" to context for event callbacks.

:bookmark: API Reference Navigation

Create a emitter instance.

var emitter = Mux.emitter()
emitter.on('change:name', function (name) {
    // do something
}) // subscribe
emitter.off('change:name') // unsubscribe
emitter.emitter('change:name', 'switer') // publish message

Instance Options

props
  • Type: Function | Object

:bookmark: API Reference Navigation

Return the initial observed property object for this mux instance.Recommend to using function which return a object if you don't want to share props option's object in each instance:

var Person = Mux.extend({
    props: function () {
        return {
            name: 'mux'
        }
    }
})
assert.equal((new person).name, 'mux')

props option could be an object:

var Person = new Mux({
    props: {
        name: 'mux'
    }
})
assert.equal((new person).name, 'mux')
computed
  • Type: Object
  • Options:
    • deps Array property dependencies. Restricton: deps's item could be keyPath (contain . and [], such as: "post.comments[0]").
    • fn Function Compute function , using as a getter
    • enum Boolean Whether the computed property enumerable or not

:bookmark: API Reference Navigation

Computed properties definition option. "fn" will be called if one of dependencies has change, then will emit a change event if "fn" returns result has change.

var mux = new Mux({
    props: {
        items: [1,2,3]
    },
    computed: {
        count: {
            deps: ['items'],
            fn: function () {
                return this.items.length
            }
        }
    }
})
assert.equal(mux.cout, 3)

Watch computed property changes:

mux.$watch('count', function (next, pre) {
    assert.equal(next, 3)
    assert.equal(next, 4)
})
mux.items.push(4)
assert.equal(mux.count, 4)
emitter
  • Type: EventEmitter

:bookmark: API Reference Navigation

Use custom emitter instance.

var emitter = Mux.emitter()
emitter.on('change:name', function (next) {
    next // --> switer
})
var mux = new Mux({
    emitter: emitter,
    props: {
        name: ''
    }
})
mux.name = 'switer'

Instance Methods

$set([keyPath, value] | props)
  • Params:
    • keyPath String property path , such as: "items[0].name"
    • value [optional]
    • or
    • props Object [optional] data structure as below:
    { "propertyName | keyPath": propertyValue }
    
  • Return: this

:bookmark: API Reference Navigation

Set value to property by property's keyPath or propertyName, which could trigger change event when value change or value is an object reference (instanceof Object). Notice: PropertyName shouldn't a keyPath (name string without contains "[", "]", "." )

var list = new Mux({
    items: [{name: '1'}]
})
list.$set('items[0].name', '')
$get(propname)
  • Params:
    • propname String only propertyname not keyPath (without contains "[", "]", ".")
  • Return: value

:bookmark: API Reference Navigation

Get property value. It's equal to using "." or "[]" to access value except computed properties.

var mux = new Mux({
    props: {
        replyUsers: [{
            author: 'switer'
        }]
    }
})
assert.equal(mux.$get('replyUses[0].author', 'switer'))

Notice: Using "." or "[]" to access computed property's value will get a cached result, so you can use "$get()" to recompute the property's value whithout cache.

// define a computed property which use to get the first user of replyUsers
mux.$computed(firstReplyUser, ['replyUsers'], function () {
    return this.replyUsers[0].author
})

var users = [{
    author: 'switer'
}]

mux.$set('replyUsers', users)

user[0].author = 'guankaishe' // modify selft

assert.equal(post.firstReplyUser, 'switer'))
assert.equal(post.$get('firstReplyUser'), 'guankaishe'))
$add([propname [, defaultValue]] | propnameArray | propsObj)
  • Params:
    • propname String
    • defaultValue [optional]
    • or
    • propnameArray Array
    • or
    • propsObj Object
  • Return: this

:bookmark: API Reference Navigation

Define an observerable property or multiple properties.

mux.$add('name', 'switer')
// or
mux.$add(['name']) // without default value
// or
mux.$add({ 'name': 'switer' })
$computed([propname, deps, get, set, enum] | computedPropsObj)
  • Params:
    • propname String property name
    • deps Array Property's dependencies
    • get Function Getter function
    • set Function Setter function
    • enum Boolean whether the computed property enumerable or not
    • or
    • computedPropsObj Object
  • Return: this

:bookmark: API Reference Navigation

Define a computed property. deps and fn is necessary. If one of deps is observable of the instance, emitter a change event after define. computedPropsObj is using to define multiple computed properties in once, each key of computedPropsObj is property's name and value is a object contains "deps", "fn". Usage as below:

// before define computed
assert.equal(mux.commentCount, undefined)
mux.$computed('commentCount', ['comments'], function () {
    return this.comments.length
})
// after define computed
assert.equal(mux.commentCount, 1)
$watch([propname, ] callback)
  • Params:
    • propname String [optional]
    • callback Function
  • Return: Function unwatch handler

:bookmark: API Reference Navigation

Subscribe property or computed property changes of the Mux instance.

var unwatch = mux.$watch('title', function (nextValue, preValue) {
    // callback when title has change
})
unwatch() // cancel subscribe

if propname is not present, will watch all property or computed property changes:

mux.$watch(function (propname, nextValue, preValue) {
    // callback when title has change
})
$unwatch([propname, ] [callback])
  • Params:
    • propname String [optional]
    • callback Function [optional]
  • Return: this

:bookmark: API Reference Navigation

Unsubscribe property or computed property changes of the Mux instance.

// subscribe
mux.$watch('name', handler)
// unsubscribe
mux.$unwatch('name', handler)
// unsubscribe all of specified propertyname
mux.$unwatch('name')
// unsubscribe all of the Mux instance
mux.$unwatch()
$props( )
  • Return: Object

:bookmark: API Reference Navigation

Return all properties of the instance. Properties do not contain computed properties(Only observed properties).

var mux = Mux({ props: { name: 'Muxjs' } })
mux.$props() // --> {name: 'Muxjs'}
$emitter(emitter)
  • Return: this | emitter

:bookmark: API Reference Navigation

Reset emitter of the mux instance. If arguments is empty, return the emitter of the instance.

var mux = Mux()
var em = Mux.emitter()
mux.$emitter(em)

var muxEmitter = mux.$emitter() // equal to em
$destroy()

:bookmark: API Reference Navigation

Destroy the instance, remove all listener of the internal emiter of the instance, free all props references.

$destroyed()
  • Return: Boolean

:bookmark: API Reference Navigation

Whether the instance is destroyed or not.

Changgelog

  • 2016/10/14
    • $set() will not return this.
    • $set({ ... }) will emit in batch

License

MIT