Fast reactive state management for observables. Inspired by virtual-dom tree-diffing algorithms and merkle-trees.
Inherits or extends vigour-observable
####simple
var State = require('vigour-state')
var state = new State()
state.subscribe({
field: { val: true }
}, (state, type) => {
// type can be "new", "update" or "remove", in this case "new"
// state is the target of the update, in this case state.field
console.log(type, state)
})
state.set({ field: 'hello' })
####any
var State = require('vigour-state')
var state = new State()
state.subscribe({
$any: { title: { val: true } }
}, (state, type) => {
console.log(type, state)
})
// fires an update, subscribed to any field with a title
state.set({ a: { title: 'a title' } })
####switch switch between different subscriptions based on conditions
var State = require('vigour-state')
var state = new State()
state.subscribe({
field: {
$switch: {
exec: (state) => state.key === 'bird' ? 'animal' : 'person',
animal: {
class: { val: true },
diet: { val: true }
},
person: {
name: { val: true },
job: { val: true }
}
}
}
}, (state, type) => {
console.log(type, state)
})
state.set({
bird: {
class: 'predator',
diet: 'mice'
},
someone: {
name: 'chris',
job: 'bird-watcher'
}
})
// set the field to bird
// this will fire updates for the birds class and diet
state.set({ field: state.bird })
// fires updates
state.bird.class.set('vegetarian')
// will not fire since the bird has no subscription on its job
state.bird.set({ job: 'accountant' })
// set the field to someone
// this will fire updates for the persons name and job
state.set({ field: state.someone })
// will not fire since the person has no subscription on its diet
state.someone.set({ diet: 'paleo' })
####root
var State = require('vigour-state')
var state = new State()
state.subscribe({
field: {
another: {
$root: { something: { val: true } }
}
}
}, (state, type) => {
console.log(type, state)
})
// does not fire, since we don't have field.another yet
state.set({ something: true })
// now it does fire
state.set({ field: { another: true } })
####self
var State = require('vigour-state')
var state = new State({
a: {
field: 'bye'
},
field: {
val: '$root.a', // makes a reference to root.a
field: 'hello'
}
})
state.subscribe({
$self: {
field: {
field: {
val: true
}
}
}
}, (state, type) => {
// fires for non-reference, field.field (hello) instead of a.field
console.log(type, state)
})
####parent
var State = require('vigour-state')
var state = new State()
state.subscribe({
field: {
another: {
$parent: { something: { val: true } }
}
}
}, (state, type) => {
console.log(type, state)
})
// does not fire, since we don't have field.another yet
state.set({ field: { something: true } })
// now it does fire
state.set({ field: { another: true } })
####test
var State = require('vigour-state')
var state = new State()
state.subscribe({
movies: {
$any: {
$test: {
exec (state) {
var query = state.getRoot().query.compute()
if (query && state.title) {
return (state.title.compute().indexOf(query) > -1)
}
},
// this is the subscription relevant for the condition
$: {
title: {},
$root: { query: {} }
},
// when the condition passes it subscribes to this pattern
$pass: {
val: 1, // only fires for remove/create or reference change
description: { val: true },
title: { val: true },
$root: {
current: { val: true }
}
}
}
}
}
}, (state, type) => {
console.log(type, state)
})
// will fire for interstellar's title and description
state.set({
query: 'interstellar',
movies: [
{
title: 'jump street',
description: 'its about streets!'
},
{
title: 'interstellar',
description: 'its about stars!'
}
]
})
// fires for interstellar (remove) and fires for jump street's title and description
state.query.set('jump')
Or any combination of the above
####inject convert any observable to a state-observable
var Observable = require('vigour-observable')
var obs = new Observable({
inject: require('vigour-state/inject')
})
obs.subscribe({ field: { val: true }}, () => {})