Context: Context bus and sysContext event
Learning objectives
In this lesson, you will learn about communication between portlets, including:
- Portal bus events: events that can be broadcast between portlets.
- Context events: shared context between portlets.
- Global context variables: workspace and global state.
Key concepts
- The bus is where inter-portal action takes place. We've already seen sysRemove, where an event is raised, potentially with parameters, and we handle the event in a UI action or a data action.
- The concept of handlers within the same portlet. For example, a button is pressed in a table within a layout and a UI action handles things to show a particular pop-up.
- Sharing context or events between portlets where we communicate over the portal bus, which is a communication bus that enables us to send and receive events with parameters. An important event is sysContext, which provides a context variable name and value as parameters. One portlet can say "I've changed the EntityId context and it is now Tim Lamont," and other portlets that are listening can respond.
Context is shared between portlets. For instance, in the Contacts workspace, the main context variable is EntityId (case is important). There are two types of participants - context setters and context receivers. All portlets with a given context in their context property listen for changes to that context variable.
CODE<Portlet context="EntityId"> ...
A portlet can declare that it is interested in more than one context variable by setting the context property to a space-separated list of context variable names. The second part of the connection is hooking up context changes to a layout in the portlet for receiving or broadcasting. This is done using either the context-form-source (broadcast) function or the context-form-target function (receive).
Layouts were previously called forms, so you will still see some functions with names like (context-form-target and so on).
Based on your work from the previous lesson, your files should appear as follows. They will also include some extra UIEvent and UIAction elements in the training:EntityList.layout
file, which are not required for this or future lessons. We recommend that you replace the contents of your training:EntityList.layout
file with the code below.
training:Contact.portal
<Portal caption="idsa.training.portal.Contact.caption">
<Tool name="toolNotifications" caption="ids.notifications" icon="icon:notifications" event="setSidebar" parameter="NOTIFICATIONS"/>
<WorkspaceRef name="refSandbox" workspace="training:Sandbox"/>
<WorkspaceRef name="refHome" workspace="mda:Home"/>
<WorkspaceRef name="refContacts" workspace="mda:Contacts"/>
<Drawer event="setSidebar" name="refNotifications" portlet="mda:NotificationDrawer"/>
</Portal>
training:Sandbox.workspace
<Workspace caption="idsa.training.workspace.Sandbox.caption" icon="icon:attach_money">
<Page name="page">
<Tab layout="cols:3 fluid:true" name="tabDetail" type="grid">
<PortletRef name="training_EntityList_portlet" portlet="training:EntityList"/>
</Tab>
</Page>
</Workspace>
training:EntityList.portlet
<Portlet>
<Composite name="composite">
<LayoutRef layout="training:EntityList" name="training_EntityList_layout"/>
</Composite>
</Portlet>
training:EntityList.layout
<Layout class="Entity">
<UIActions>
<UIAction event="sysProperties">
<Popup association="tblEntityList" edit="true" screen="training:mda:EntityProperties"/>
</UIAction>
</UIActions>
<Composite name="composite">
<Table caption="idsa.training.layout.EntityList.caption" name="tblEntityList" rows="(@)">
<Menu name="mnuRightClick">
<Item caption="ids.edit2" event="sysProperties" icon="edit" name="mitProperties"/>
<Item event="sysRemove" name="deleteItem"/>
</Menu>
<Column name="colType" caption="idsa.training.layout.EntityList.type" icons="type iconDefault"/>
<Column name="colIcon" caption="idsa.training.layout.EntityList.icon" icons="(image . image)(data . mimeData)(type . mimeType)" texts="initial"/>
<Column name="colName" caption="idsa.training.layout.EntityList.name" length="100" values="fullName"/>
</Table>
</Composite>
</Layout>
training:mda:EntityProperties.dialog
<Dialog caption="ids.caption.editPopup">
<Composite cols="2" name="composite">
<LayoutRef layout="mda:EntityPropertyDashboard" head="true" name="mda_EntityPropertyDashboard_layout"/>
<Switch caption="ids.detail" head="true" name="grpDetailLayout" span="2" value="mda_EntityPropertyDashboard_layout">
<Composite case="UserPerson" name="compUser">
<LayoutRef association="mda_EntityPropertyDashboard_layout" layout="mda:UserPersonEditDetail" head="true" name="mda_UserPersonEditDetail_layout"/>
</Composite>
<Composite case="Person" name="compPerson">
<LayoutRef association="mda_EntityPropertyDashboard_layout" layout="mda:PersonEditDetail" head="true" name="mda_PersonEditDetail_layout"/>
</Composite>
<Composite case="Company" name="compOrg">
<LayoutRef association="mda_EntityPropertyDashboard_layout" layout="mda:CompanyEditDetail" head="true" name="mda_CompanyEditDetail_layout"/>
</Composite>
</Switch>
<LayoutRef association="mda_EntityPropertyDashboard_layout" head="true" layout="mda:EntityAuditFields" name="mda_EntityAuditFields_layout" span="2"/>
</Composite>
<Actions layout="mda:PopupButtons" name="mda_PopupButtons_layout"/>
</Dialog>
idsa.training.en.strings
idsa.training.portal.Contact.caption=My Training Application
idsa.training.workspace.Sandbox.caption=Sandbox
idsa.training.layout.EntityList.caption=Entity List
idsa.training.layout.EntityList.type=Type
idsa.training.layout.EntityList.icon=Icon
idsa.training.layout.EntityList.name=Name
Setting context
Portlets that want to set context, such as a navigator portlet, use the context-form-source script in their initialization. In the following example, the portlet will listen for changes in the EntityList layout and broadcast a sysContext event to the bus for the EntityId context variable.
Example
(context-form-source (this'view) "EntityId" "training_EntityList_layout")
Receiving context changes
In order to receive context changes so they show up-to-date and correct information, portlets use the context-form-target script in their initialization. In the following example, the portlet listens for sysChange
events on the bus to the EntityId
context, and updates the EntityDetail
layout when that occurs.
Example
(context-form-target (this'view) "EntityId" "training_EntityDetail_layout" '())
Linked through their association property, other layouts in the portlet associated with this primary layout are also updated.
The arguments to these functions are:
view | View | The portlet view. |
var | string | The context variable name. |
layout | string | The layoutRef name. |
args | Optional | An association or a where clause function in the following format (: association value) or (: whereFunc value) |
Learning activity
Update your
training:EntityList
portlet as follows.training:EntityList.portlet
XML<Portlet context="EntityId"> <Script><![CDATA[(context-form-source (this'view) "EntityId" "training_EntityList_layout")]]></Script> <Composite name="composite"> <LayoutRef layout="training:EntityList" name="training_EntityList_layout"/> </Composite> </Portlet>
We added the following to the existing definition:
- The context property to the portlet so the system knows that our portlet is interested in
EntityId
. - The context-form-source script entry that says, "Set the
EntityId
context on the context bus based on the current selection intraining_EntityList_layout
."
- The context property to the portlet so the system knows that our portlet is interested in
Update the Sandbox workspace to include the example AFL bus portlet. This portlet, among other things, displays changes to the
EntityId
context variable as they occur.Sandbox.workspace
XML<Workspace caption="idsa.training.workspace.Sandbox.caption" icon="icon:attach_money"> <Page name="page"> <Tab caption="IDS_DETAIL" layout="cols:3 fluid:true" name="spltDetail" type="grid"> <PortletRef name="training_EntityList_portlet" portlet="training:EntityList"/> <PortletRef name="aflBus" portlet="app/bus"/> </Tab> </Page> </Workspace>
- Save, reload the UI, and reseed.
- Click around in the list.
You will see the results of theEntityList
updating theEntityList
context variable and the AFL bus app displaying it. To listen for the change in an MDA portlet:
This is almost the same as the work we did in the
EntityList
portlet, but instead of setting the context, we will respond to it.Create a new layout called
training:EntityDetail
and update the layout's source with the following code:EntityDetail.layout
XML<Layout class="Entity" caption="idsa.training.layout.EntityDetail.caption"> <Composite name="composite"> <Label caption="firstName" head="true" name="lblFirstName"/> <Label caption="lastName" name="lblLastName"/> </Composite> </Layout>
Add the following to the
idsa.training.en.strings
file.CODEidsa.training.layout.EntityDetail.caption=Entity Detail
The layout is bound to the
Entity
class.Create a new portlet called
EntityDetail.portlet
which will listen to theEntityId
context, contain the layout, and set the context of the layout whenever a change is detected. Update the source of the portlet with the following code:training:EntityDetail.portlet
XML<Portlet context="EntityId"> <Script><![CDATA[(context-form-target (this'view) "EntityId" "training_EntityDetail_layout" ())]]></Script> <Composite name="composite"> <LayoutRef layout="training:EntityDetail" name="training_EntityDetail_layout"/> </Composite> </Portlet>
The portlet is using the context-form-target function to set the current entity for the layout.
Add the new portlet to the workspace. Update the source of the
training:Sandbox.workspace
as follows:training:Sandbox.workspace
XML<Workspace caption="idsa.training.workspace.Sandbox.caption" icon="icon:attach_money"> <Page name="page"> <Tab caption="IDS_DETAIL" layout="cols:3 fluid:true" name="spltDetail" type="grid"> <PortletRef name="training_EntityList_portlet" portlet="training:EntityList"/> <PortletRef name="training_EntityDetail_portlet" portlet="training:EntityDetail"/> <PortletRef name="aflBus" portlet="app/bus"/> </Tab> </Page> </Workspace>
- Stop and restart your server.
- Re-seed and refresh your browser. As you click through the list, you should see the Entity Detail portlet updating its values to match the selected entity.