3.10Communicating between widgets/scripts/UDIXes

Different instances of a widget, script, or UDIX can share saved "category" settings as described above, with notifications when the shared settings change.

It is also possible for different widgets, scripts, and UDIXes to send messages to each other without permanent data storage. This comes in three parts.

Every widget, script, or UDIX has an ID, Framework.id.

A component which is interested in talking to another component sends out a broadcast message.

The other component(s) receive the broadcast message, in OnMessage(), and can see the sender's ID. They can now send a direct message back. On receipt of a direct message (or a broadcast message), the original sender can now see the recipient's ID, and send further direct messages.

You send messages using Framework.PostMessage(). The only compulsory parameter is an FXB.Message object, which you can construct as follows. The initialisation must have a msgType property, and can then contain any other data that you want.

The framework has special message types for widgets to exchange ad hoc data. There are BROADCASTx messages which can be sent without knowing a recipient's ID, and GENERICx messages which can be used for direct, peer-to-peer communication.

For example:

var myMessage = new FXB.Message({

msgType: FXB.MessageTypes.BROADCAST1, // A msgType is compulsory for FXB.Message

myAction: "Want to chat?",

anyOtherData: {

moreData: 231,

},

someProperty: someValue

});

Framework.PostMessage(myMessage);

Broadcast messages are sent to all other widgets, scripts, and UDIXes in the platform. Those can then listen for broadcasts in OnMessage(), and choose to respond. For example:

Framework.OnMessage = function(Msg) {

if (Msg.is(FXB.MessageTypes.BROADCAST1)) {

// Is this a message which we understand?

if (Msg.myAction && Msg.myAction == "Want to chat?") {

// Send a response

var response = new FXB.Message({

msgType: FXB.MessageTypes.GENERIC1,

_to: Msg._from, // The _from of the Msg gives us the sender's ID

myResponse: "Yes, I want to chat"

});

Framework.PostMessage(response);

}

}

};

When a component receives a message, the _from property tells it the sender's ID. This gives it the ability to construct a direct message back to the sender, by setting the _to property in a response message - as in the example above.

The original sender could then listen for acceptance of its original broadcast as follows:

Framework.OnMessage = function(Msg) {

if (Msg.is(FXB.MessageTypes.GENERIC1)) {

// Is this a message we understand?

if (Msg.myResponse && Msg.myResponse == "Yes, I want to chat") {

// The recipient of broadcast knows this sender's ID,

// and this sender now knows the responder's ID because

// it is the _from of this response message

}

}

};

Once a direct connection is established, there is a further mechanism which can simplify the sender/response code. The Framework.PostMessage() function has an optional second parameter: an asynchronous callback which receives responses. This is called if a recipient of a message uses Framework.Respond().

For example, once they have each other's IDs, one component can send a message to another component as follows:

Framework.PostMessage(myNewMessage, function (Msg) {

// Callback triggered by the recipient using Respond().

// The response message also passes through OnMessage(), but handling it "inline"

// like this will often be simpler and cleaner.

});

The recipient triggers the response callback in the sender by using Framework.Respond() instead of Framework.PostMessage(). The Respond() function takes two parameters: the new message to send back, and the message to respond to. For example:

var myResponse = new FXB.Message({

msgType: FXB.MessageTypes.GENERIC1,

myData: "some communication"

});

Framework.Respond(myResponse, someOriginalMessage);

(If you are using Respond(), you don't need to set an explicit _to on the message you are sending. Respond() fills this in for you.)

The one thing to note is that an asynchronous callback for PostMessage() is only called once (or not at all, if nothing responds). If you use an asynchronous callback with a broadcast message, then it will only receive the first response, and be terminated after that. If there are second and subsequent responses from other components, then those will be ignored (unless also separately handled in OnMessage).

In other words: an asynchronous callback on PostMessage() is great for direct, peer-to-peer messages, but generally not suitable for broadcast messages unless you are specifically only expecting a single response.