Documentation
The nFlow
API is designed to be simple and easy to use.
Essentially, the heart of nFlow
is only 3 methods : create
, on
and emit
.
Since in nFlow
there is only one type of object, the same API applies to every object created or emitted.
Whether they are used as dispatchers, events, stores or controllers - they are the same type of objects and share the same API.
API Reference
create
flow.create([name], [...data])
Creates a new flow
object.
Arguments
[name]
(String): the name of the new flow object.[...data]
(*): the data to be stored in the flow object. Can be of any type.
Returns
- the new
flow
instance
Note: The parent of the new object is automatically set to the flow object it was created from.
Example
let a = f.create('a')
let b = f.create('b')
let c = a.create('c')
let d = a.create('d')
Aliases
The following command chains are identical:
.create('a', someData)
.create('a').data(someData)
.create().name('a').data(someData)
on
flow.on(name, ...listeners)
Adds a listener to the flow object
Arguments
name
(String): the name of the listener. The listener will be invoked if a flow object travelling through the current node has exactly the same name...listener
(Function): The callback function to be invoked. If you specify multiple listeners, they will called in sequential order:
flow.on('registerUser', validateName
, validateEmail
, validatePassword
, register)
Returns
- setter: the new
flow
instance - getter: the currently registered listeners:
.on('foo') // returns [listener1, listener2]
.on()
// returns { foo: [listener1, listener2], bar:[listener3] }`
Deleting and Augmenting Listeners:
flow.on('foo', a,b,c)
// subsequent calls on the same listener will OVERWRITE the previous listeners:
flow.on('foo', d,e) // a,b or c WILL NOT be triggered
// setting a listener to null DELETES ALL listeners:
flow.on('foo', null) // no listeres will be triggered
Example
// in services.js:
...
var services = f.create('service')
// in user-service.js:
...
services
.create('user')
.on('login' , login)
.on('logout' , logout)
.on('register', validateName
, validateEmail
, validatePassword
, register)
// in ui.js:
...
var ui = f.create('ui')
var form = ui.create('form')
...
// when the user click on the submit button:
form.emit('register', email, name, password)
emit
foo.emit([name], [...payload])
Emits an event.
The
.emit
API has two distinct behaviours:foo.emit() // turns foo into an event and emits it foo.emit('bar') // creates bar and emits it on foo
The following 2 operations are essentially the same:
foo.emit('bar')
foo.create('bar').emit()
Arguments
[name]
(String): the name of the new flow object to be created and emitted. If no name is given, the current flow object will be emitted....payload
(*): the data to be carried in the event. Multiple parameters are accepted:
a.on('registerUser', function(name, email, password){ ... })
...
b.emit('registerUser', name, email, password)
Returns
- the emitted
flow
instance
Listener Context
Listeners are invoked in the context of the emitted event.
In the listeners the this keyword always refers to the invoking event.Since events are also flow objects, you can dispatch further events on them!
name
flow.name() // returns the name of the flow object
flow.name('foo') // sets the name of the flow object
Getter/Setter
Arguments
name
(String): the name of the new flow object.
Returns
- Getter:
name
(String): the name of the flow object - Setter: the
flow
instance
call
flow
.create('foo')
.call(callback) // calls callback with the foo flow object
.create('bar')
Invokes the callback function, passing in the current flow object and any optional parameters. Useful for getting an instance of the flow object in the middle of a method chain.
Arguments
callback
(Function): callback function to be called with the current flow object.[...argument]
(*): additional parameters to be passed into callback
Returns
flow
: the current flow instance
data
flow.data() // returns the data stored in the flow object
flow.data(...args) // sets some data to be stored in the flow object
Getter/Setter
Arguments
[...data]
(*): the data to be stored in the flow object. Can be of any type.
Returns
- Getter:
...data
(*): the data stored in the flow object - Setter: the
flow
instance
Note: If multiple data objects are stores in a flow instance, the getter will return them in an array,
eg.: setting.data(foo, bar)
, then calling.data()
will return[foo, bar]
children
flow.children() // returns an array of all child flow objects.
Returns an array of direct child nodes. To get all downstream nodes recursively, use the .get.all
API
Getter
only. To add a new child use f.create('new-child-name')
. To add an existing child, use: child.parent(f)
Returns
[...flow]
An array of all immediate child flow objects
Note: this API only returns the immediate children. If you need to access all child objects recursively, use the
.get.all
API
Example
f.create('a')
f.create('b')
.create('d')
f.create('c')
f.children() // returns [a,b,c]
get
aliases for get
:
find
flow.get(matcher, recursive)
Getter
only
The get
API searches all direct children and returns the first result. If the recursive
parameter is set to true, indirect children are searched, too
Arguments
matcher
(String or Function): the name of the flow object to find, or a mathcer function[recursive]
(Boolean): iffalse
: only immediate child nodes are searched
Returns
- flow (flow): the first flow instance that passes the matcher test
Note:
Matcher Functions are invoked multiple times with a single parameter: the currently tested flow object. If the function returnstrue
, the flow is added to the result.
Example
f.create('a', 9)
f.create('b')
f.create('c', 9)
.create('d')
f.get('a') // returns a
f.get('d') // returns null (since d is not a direct child)
f.get('d', true) // returns d
f.get(child=>child.data()==9) // returns a, the first node where data = 9
get.all
aliases for get.all
:
find.all
flow.get.all(matcher, recursive)
Getter
only
Same as the get
API, but ALL matching nodes are returned
Arguments
matcher
(String or Function): the name of the flow object to find, or a mathcer function[recursive]
(Boolean): iffalse
: only immediate child nodes are searched
Returns
[...flow]
(Array): all flow instances that pass the matcher test
Example
f.create('a', 9)
f.create('b')
f.create('c', 9)
.create('d')
f.get.all('a') // returns [a]
f.get.all('d') // returns [] (since d is not a direct child)
f.get.all('d', true) // returns [d]
f.get.all(child=>child.data()==9) // returns [a,c]
parent
f.parent()
f.parent(newParent) // re-parents the node to newParent
f.parent(null) // detaches the current node
Detaches or re-parents the current node.
Getter
/Setter
Arguments
newParent
(flow): a flow object to reparent, ornull
to detach the current node
Returns
- getter:
parent
(flow): The current parent (ornull
if the current node is detached) - setter:
flow
(flow): the current node
Example
var a = f.create('a')
a.create('a1')
a.create('a2')
f.create('b')
a.parent(null
Note:
Setting.parent(null)
will detach the branch, turning it into a new tree. No events will travel in or our between isolated trees.
parents
f.parents()
Retuns an array of all parents, starting from the elements parent, going upstream until a root node is found.
Getter
only
Returns
...parents
(Array): An array of flow objects
Example
var a = f.create('a')
var b = f.create('b')
var c = a.create('c')
var d = a.create('d')
var e = d.create('e')
c.parents() // returns [d,a,f]
Note:
It is possible to introduce cyclic dependency by setting one of the parents'.parent
node to a child node. In this scenario.parents()
will return an array of all unique parent nodes
status
f.status()
Returns the current status of the node.
Getter
only.
Returns
status
(String): One of the following status indicators:flow.status.IDLE
:
The default state of a flow objectflow.status.FLOWING
:
The flow object has been emitted and is currently traversing the treeflow.status.STOPPED
:
The flow object has been stopped during propagation.flow.status.COMPLETED
:
The flow object has been delivered to all listeners.flow.status.CANCELLED
:
The flow object has been cancelled.
No further events will be emitted or received on cancelled nodes or any of their child nodes
direction
f.direction()
f.direction(flow.direction.UPSTREAM)
Defines the flow direction of an emitted node. The flow direction defines how an emitted flow object traverses the tree when it gets emitted.
Getter
/Setter
Returns
- if setter:
flow
(flow): the current node if getter:
direction
(String): One of following direction indicators:flow.direction.DEFAULT
:
The default flow direction. When the node is emitted, it travels upstream until it finds the root node, then travels downstream to reach all recipients.
Downstream traversal is depth-first.flow.direction.UPSTREAM
:
When the node is emitted, it travels upstream until it finds the root node, then it stops.flow.direction.DOWNSTREAM
:
When the node is emitted, it travels downstream until it has reached all recipients. The downstream traversal is depth-first.flow.direction.NONE
:
When the node is emitted, it only notifies listeners attached to itself and the emitter node, then it stops.flow.status.ROOT
:
When the node is emitted, it flows upstrem to the root node, and only notifies listeners on that node.
Note:
If Circular Dependency is detected in the tree (ie. a parent has been reparented as a downstream child), event delivery stops as soon as all unique listeners have been notified.
cancel
flow.cancel()
Setter
only.
Cancelling a flow object has the following effects: - If the object is used as an event, it will immediately stop invoking subsequent listeners - No further events can be dispatched or received on cancelled flow objects or their downstream child objects
Returns
- the current flow
object
Note
Cancelling a flow object effectively cancels all of its child objects recursively.
Example
var a = f.create('a')
var b = f.create('b')
var c = a.create('c')
var d = a.create('d')
a.cancel()
isCancelled
flow.isCancelled()
Getter
only.
Returns
- (Boolean) true if the current flow object or any of its parents have been cancelled.
stopPropagation
flow.stopPropagation()
Setter
only.
Invoking .stopPropagation()
will stop delivering the event to further listeners.
Returns
- the current flow
object
Difference between
stopPropagation
andcancellation
:Cancelling an event has a lasting effect: no further events can be dispatches or received on a cancelled flow object or its children(recursively).
In contrast -
stopPropagation
simply stops the current event delivery - but the flow object stays active - you can still send or receive events on them.
propagationStopped
flow.propagationStopped()
``
Getter` only.
Returns
- (Boolean) true if
.stopPropagation()
has been called on the current flow object
guid
flow.guid() //returns 1234
Getter
only.
Returns
- the unique identifier of the flow object.
toString
flow.toString()
Getter
only.
Returns
- a stringified representation of the current flow object. Useful for logging.
toObj
flow.toObj()
Getter
only.
Returns
- a static object representation of the current flow object:
{
name: 'foo',
guid: 1234,
status: 'IDLE'
listeners:['hello']
children:[
name: 'bar',
guid: 2345
]
parent:{
name: 'a'
guid: 5432
}
}