Namespacing¶
FootworkJS enables you to organize your code into namespaces
. Namespaces boil down to a simple string
identifier which is used to segment off one area from another.
By keeping your modules separate and using a namespace
to communicate and share state you are more easily able to keep your application loosely coupled.
Publish / Subscribe¶
Pub/Sub is a messaging pattern used to aide in decoupling by allowing communication between separate areas of your application without the need of direct references.
With Footwork-based code pub/sub is even more necessary because any declarative viewModel, dataModel, and router instances (along with components) you create will not give you direct references to them. Why? Because you don't explicitly instantiate them.
So in order for you to tell these modules to do things (outside of binding your UI to them) you will need to pass them messages. Footwork facilitates this via its namespace
feature.
Note
Each namespace
instance using the same string identifier communicates on the same message bus.
This means that if you create a namespace
in two places using the same string identifier they will receive the same messages.
Subscribing to Messages¶
To receive a message you must first subscribe to its topic, in Footwork this is done by calling subscribe
on a namespace
instance and providing it the topic as well as a handler callback.
For example:
// first create the namespace instance we need to setup our subscription handler on var blahNamespace = fw.namespace('blah'); // create the subscription passing it the topic and callback handler var subscription = blahNamespace.subscribe('something-happened', function (thisThingHappened) { console.log(thisThingHappened); });
In the example above you can see a namespace
of blah being instantiated and a subscription handler for the something-happened topic
. The handler defined simply logs any message it receives to the console.
Publishing a Message¶
In the preceding example, it showed how to create a subscription
to the topic something-happened on the namespace
blah. Lets publish a message to it from some other place in our code:
/** * We need access to the namespace in order to publish a message to it * so we create another instance using the same string identifier as before. */ var alsoBlahNamespace = fw.namespace('blah'); /** * Now lets publish a message, all subscriptions listening to the * 'something-happened' topic will receive it. */ alsoBlahNamespace.publish('something-happened', 'this thing happened'); // console logs: 'this thing happened'
The example above shows a new instance of the same blah namespace
being created, and then a message published on it using the same something-happened topic
we subscribed to in the earlier example. Because we are sending a message on the same namespace
and topic
the handler we setup prior then receives the message and logs it to the console.
Request / Response¶
At times you may need to ask a different area of your program for a piece of information (or state). Footwork helps with this by providing an easy way to synchronously request for data via its namespace
.
Listening for Requests¶
To listen for a request you setup a requestHandler
on a namespace
for a specific topic
. This is shown here:
var blahNamespace = fw.namespace('blah'); var requestHandler = blahNamespace.requestHandler('what-happened', function () { return 'this thing happened'; });
You can also optionally receive a parameter from the requester:
var requestHandler = blahNamespace.requestHandler('what-happened', function (param) { return 'this thing happened with ' + param; }); var response = blahNamespace.request('what-happened', 'that'); // response === 'this thing happened with that'
Requesting data¶
After creating the request handler, issuing a request is as simple as request
'ing it:
var alsoBlahNamespace = fw.namespace('blah'); var thingThatHappened = alsoBlahNamespace.request('what-happened'); // thingThatHappened === 'this thing happened'
Using a namespace
instance with the same blah string identifier as before we request the data. The previously setup handler responds to it and returns our requested data.
Handling Multiple Responses¶
You may be asking, what happens if I setup multiple handlers for the same request topic
on a namespace
? Well, that depends...
- Receiving only the first response
By default, only the first response is returned.
var blahNamespace = fw.namespace('blah'); var requestHandler = blahNamespace.requestHandler('what-happened', function () { return 'this thing happened'; }); var anotherRequestHandler = blahNamespace.requestHandler('what-happened', function () { return 'this other thing happened'; }); var thingThatHappened = blahNamespace.request('what-happened'); console.log(thingThatHappened); // console logs: 'this thing happened'
- Receiving all responses
You can optionally pass true
as the third parameter to request
, telling Footwork to return all of the responses it receives:
var thingsThatHappened = blahNamespace.request('what-happened', null, true); console.log(thingsThatHappened); // console logs: ['this thing happened', 'this other thing happened']
Sharing State¶
Pub/Sub and request/receive are great, but what if you just want to share/sync some data across different areas of your code? Footwork provides an easy way to do that via its broadcastable / receivable functionality:
Broadcast / Receive¶
A broadcastable and receivable allow you to (in a loosely coupled manner) share data and state between two different areas of your application, keeping them in sync as they are altered.
// share this value as 'broadcastable' on the 'someNamespace' namespace var broadcastable = fw.observable().broadcast('broadcastable', 'someNamespace'); // receive/sync the value 'broadcastable' from the 'someNamespace' namespace var receivable = fw.observable().receive('broadcastable', 'someNamespace'); // receivable() === undefined broadcastable('someValue'); // receivable() === 'someValue'
For more information see broadcastables / receivables.
Lifecycle¶
Any subscriptions or request handlers setup on a namespace
will hang around in memory until disposed of.
As you may have seen above, a subscription
is returned each time you setup a request handler or subscription
. You can explicitely dispose of a single subscription using its dispose
method:
var subscription = blahNamespace.subscribe('something-happened', function (thisThingHappened) { console.log(thisThingHappened); }); blahNamespace.publish('something-happened', 'this thing happened'); // console logs: 'this thing happened' // dispose of the subscription handler setup above subscription.dispose(); blahNamespace.publish('something-happened', 'this thing happened again'); // console does not log anything
Another way to dispose of handlers is to dispose of the namespace
they were created on. Each namespace
saves a record of each subscriptionn or handler that is setup...so once the namespace
is disposed it then disposes all of its subscriptions/handlers as well.
blahNamespace.subscribe('something-happened', function (thisThingHappened) { console.log(thisThingHappened); }); blahNamespace.publish('something-happened', 'this thing happened'); // console logs: 'this thing happened' // dispose of the namespace which then disposes its subscription handler setup above blahNamespace.dispose(); blahNamespace.publish('something-happened', 'this thing happened again'); // console does not log anything
Note
If you are using a namespace
that is attached to a viewModel, dataModel, or router then it will also be disposed of when the instance it is attached to is disposed of (and of course, its handlers/subscriptions).
Tools¶
Get the string identifier for a namespace¶
To get the string identifier of an instantiated namespace
you call the getName
method:
var blahNamespace = fw.namespace('blah'); console.log(blahNamespace.getName()); // console logs: 'blah'