« return to the patterns overview

Action Patterns

In LaxarJS applications, actions allow widgets and activities to give their collaborators the opportunity to react to "something that happened". Usually, "something" is a user-interaction: A confirmation button was clicked, a selection was changed or a backend call was completed on behalf of the user.

Other widgets may respond to arbitrary action requests by listening to their configured topics, and taking an action appropriate for them: They might open a popup, start navigation, perform a HTTP request, ask to validate or save some resources, clear their own resources and so on. When widgets respond to an action request, they can do so asynchronously using the [will/did]-mechanism. This means that actions can have a duration, which is useful for longer running tasks such as performing a search. The duration can in turn be used by yet other widgets, for example to show a progress indicator every time that an action on the page runs for more than, say, 200 milliseconds.

If you are familiar with Qt's signal/slot mechanism, you may think of an action as the named, asynchronous counterpart to an n:m signal/slot connection.

Action Requests and Will/Did-Responses

As with resources, the page configuration determines which widgets share action topics: If a widget offers to publish an action, but no topic was configured for that action, it should not publish an event. Similarly, if a widget offers to respond to some action, but no topic was configured, it should not subscribe to action requests.

The takeActionRequest, willTakeAction and didTakeAction Events

A widget (the action initiator) may request for action to be taken by publishing a takeActionRequest. Collaborators (action handlers) capable and configured to perform a corresponding action respond by publishing a willTakeAction event. After they have completed performing their action, possibly asynchronously, the collaborators publish a didTakeAction event.

Event name Payload Attribute Type Description
takeActionRequest.{action} published by any widget to request for some action being taken
action string the topic through which respondents are connected (used in the payload as well as in the event name)
anchorDomElement string If applicable: the ID of a DOM element where the action originated
willTakeAction.{action} published by a widget that is about to perform some action
action string see above
didTakeAction.{action}.{outcome} published by a widget that has completed its action
action string see above
outcome string ERROR or SUCCESS (used in the payload as well as in the event name)

The anchorDomElement that can be sent along with the takeActionRequest is useful to display popover hints right next to the UI element that was activated by the user. This information exposes implementation details of the sender, so respondents should take care not to modify the sender DOM and not to rely on a specific structure.

The outcome that is sent with the didTakeAction response indicated if the (assumed) user intent could be satisfied, because of an error condition that could not be handled (such as a network problem). If the outcome is ERROR, the initiator should signal this to the user if appropriate, and the handler should publish a didEncounterError event with details on the problem.

Although any additional information to a takeActionRequest or didTakeAction event payload may not be understood by a random third party widget, it may be part of a unidirectional data flow. For this paradigm it is important, that for any resource only one source exists, that is allowed to replace this resource completely or update parts of it by means of resource replace and update mechanisms. Any other widget collaborating on the same resource may change this resource locally, but is not allowed to publish any updates to it directly or even replace it. Instead such a widget will send a takeActionRequest event with the changes it would like to see for a certain resource as additional payload, ideally as functional request instead of the changes already incorporated into the resource. The actual change can then be achieved directly by the activity being the master for the resource or by means of e.g. a REST request.