Distributed Store

The Distributed Store reduces complexity by operating as a central repository. This reduces the number of connections that windows need to maintain. The Distributed Store hosts business logic which can be invoked by any window that it’s plugged into. This lets the store synchronize state across window boundaries. Multiple windows can share data, yet remain loosely coupled. Each window now only needs to be aware of a data model, not all the other windows.

This is elegant because no one window ends up with an explicit dependency on any other. Components in this architecture can be designed so that they depend only on a shared data model. Operating in this environment, components can come and go throughout the lifetime of a user’s session. When a component is instantiated, it immediately gains state via the store. Values can accurately be displayed to the end user and the component can begin participating with other like-minded components in modifying that state.

Creating a Distributed Store

Stores are used to save and retrieve data either locally or globally. This data is not persistent.

You can add listeners at multiple levels, either at the store level (mystore) or at an individual attribute level within the store's values (value1.value2). Listeners allow a component to receive updated data as soon as the store changes. Fields are stored within the store as key/value pair.

To create a store, use the following:

var values = {
	item1: "value1",
	item2: {
		item3: "value2",

	{ store: "store1", global: false, persist: false, values: values },
	function (err, storeObject) {}

This returns an instance of the store that you can now interact with. If a store already exists by the provided name, a store is not created and the previously created store is returned.

createStore has the following options:

  • store - The name of the store that you would like to create.
  • global - If true, the store can be accessed by any component/service within Finsemble. If false, the store can only be accessed by the current component/service.
  • persist - Whether to persist the values of the store to storage. The store must be global to use this flag.
  • values - The default values you'd like to have in the store.

If you know a store already exists, you can do the following:

FSBL.Clients.DistributedStoreClient.getStore({ store: "storenamehere" }, function (err, storeObject) {});

Using the Distributed Store

Seeding values

Distributed stores that are persistent can be seeded using a foundation. The foundation is capable of merging lists with any previously existing state. The merging of two lists will take a priority based on a config variable that's passed to each store. This means its possible to prioritize state or foundation on every Finsemble reload.

"servicesConfig": {
	"distributedStore": {
		"initialStores": [
				"name": "My-Store",
				"foundation": { ... }

name - tells the service which store this is a foundation for. If a store doesn't already exist by that name, it will be created when the service starts up.

foundation - This object should contain all the values to seed to the store

Getting values

getValue allows you to get a value from the store. You must provide the value that you'd like to retrieve and a callback. If the value is a top level attribute then you can just pass in a string like so:

store.getValue("item1", function (err, value) {});
// value1

Here, we get the value of item1 (value1) set above. You can also get nested values from your store:

store.getValue("item2.item3", function (err, value) {});
// value2

getValues is similar to getValue, but it returns an array of values.

store.getValues(["item1", "item2.item3"], function (err, value) {});
// [value1,value2]

Setting values

Just like getting a value, you can set a value in a store in two ways:setValue and setValues. You can set a value at any level within your store. Example 1 shows how to set a value at the top level of your store. Example 2 shows how to set a nested value. When a value is set, listeners are fired at every level that is changed. Listeners are covered below. You can set a nested value that does not exist and it will create the value tree to that point.

//Example 1
store.setValue({ field: "field1", value: "new value" }, function (err) {});
//Example 2
store.setValue({ field: "field1.field2", value: "new value2" }, function (err) {});
		{ field: "field1", value: "new value" },
		{ field: "field1.field2", value: "new value2" },
	function (err) {}

Removing values

Removing a value is very similar to setting a value; however, you only need to specify the field you want to remove. Note Note: Right now, this just sets the value of the removed value to null.

store.removeValue("field1", function (err) {});
store.removeValues([{ field: "field1" }, { field: "field1.field2" }], function (err) {});


Listeners are where the power of the store comes into play. Listeners allow you to receive notifications when a specific field has changed. Just like setting/getting a value, you can listen at any level you want to. addListener takes the following arguments:

  • field - This is the attribute within your store to which you're listening for changes. Listeners will get changes to anything to the current level and below.
  • function - This is the function you want triggered on a change to the store. You should not use an anonymous function here. Since anonymous functions can't be references, you won't be able to remove any listener that is created with one.
  • callback - A callback will get called after the listener is set. It's optional.

Here are some examples of how to useaddListener:

function myFunction(err, updatedData) {
	//handle your changes here

//Store level listener:
store.addListener(myFunction, function (err) {});

//Field specific listener
store.addListener({ field: "someField" }, myFunction, function (err, storeValues) {});

//Nested field specific listener
store.addListener({ field: "thisField.thatField" }, myFunction, function (err, storeValues) {});

We also have an addListeners function that takes array of values for the field. The field parameter can take data in the following formats:

var myFunction = function (err, data) {};
var commonListener = function (err, data) {};

//With this method you can specify a different listener for each field provided.
		{ field: "field1", listener: myFunction },
		{ field: "field2", listener: myFunction },

//If you only want to specify specific listener functions for some of the fields and use a common listener for others then you would want to use this method.
store.addListeners([{ field: "field1" }, { field: "field2", listener: myFunction }], commonListener, cb);

// If you just want to use a common listener function for all fields, this is the method to use.
store.addListeners(["field1", "field2"], commonListener, cb);

Removing listeners

To remove a listener, you just need to provide the field and the function used for that listener. The callback returns a boolean which states if the listener was removed.

var myFunction = function (err, data) {};
//Store level remove
store.removeListener(myFunction, function (err, bool) {});
//Field level remove
store.removeListener({ field: "field1" }, myFunction, function (err, bool) {});

Removing a store

Removing a store is as easy as stating it's name and it's scope. If you don't specify scope, Finsemble will try to remove it locally first and then look globally. If the removal is successful, the callback will return true for the bool property.

FSBL.Clients.DistributedStoreClient.removeStore({ store: "store1", global: true }, function (err, bool) {});

check   The Distributed Store reduces complexity by operating as a central repository. This reduces the number of connections that windows need to maintain.

Further reading

Advanced information about the Distributed Store can be found in the Distributed Store Client documentation.

Read the Router tutorial to better understand how Finsemble sends and receives messages.