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): if false: 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 returns true, 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): if false: 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, or null to detach the current node

Returns

  • getter: parent (flow): The current parent (or null 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 object
    • flow.status.FLOWING:
      The flow object has been emitted and is currently traversing the tree
    • flow.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 and cancellation:

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
  }
}