Skip to main content
Skip table of contents

Navigator detail pages

In this lesson, we explore the second important part of the navigator pattern - the detail page.

Learning objectives

  • Learn to create meaningful pages for the Contact, Company, and User cases.

In this lesson, we will focus on the structure of the detail page and not the specifics of different card patterns. For information on configuring banner, chart, and list cards as well as control details, see the relevant lessons in the Cards and the Controls sections.

Key concepts

We often use the navigator pattern to present a list of items, for example, Person, Opportunity, Service Request, and so on, which allows you to further navigate to the details for a particular item. Key workspace concepts include:

  • Navigator - an optional workspace portlet that displays a list of items. Clicking on an item in the list typically allows you to navigate to a detail page.
  • Page - arranges portlets into meaningful functional groups. You can display different pages depending on characteristics of the selected item.
  • Banner - an optional banner portlet to display summary information at the top of a page.
  • Tabs - optional grouping of portlets within a page.

The detail part of the navigator pattern is implemented as a page, or pages, with a summary banner portlet at the top with a number of tabs containing card portlets underneath. This arrangement looks something like this.

Detail part of navigator pattern implemented as a page

In simple cases, there is one detail page defined. For more involved cases, where the navigator list contains many different types, we define one page per subclass. For example, the Entity class hierarchy, looks like this:

Entity class hierarchy

Similar to what we did with dynamic columns based on type (Person, Company, and User) in the previous lesson, we will create a page per major subclass of Entity.

Entity Navigator → sysDetail event displays one of:

  • Contact Page
  • Company Page
  • User Page

depending on the item selected in the navigator list.

In preparation for the learning activities in this lesson, make sure that your files include the following code. If not, copy this code into your files before continuing.

training:Contact.portal

XML
<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

XML
<Workspace caption="idsa.training.workspace.Sandbox.caption" icon="icon:attach_money">
   <Navigator name="training_EntityList_portlet" portlet="training:EntityList"/>
   <Page name="page">
      <Tab caption="IDS_DETAIL" layout="cols:3 fluid:true" name="tabDetail" type="grid">
         <PortletRef name="training_EntityDetail_portlet" portlet="training:EntityDetail"/>
         <PortletRef name="aflBus" portlet="app/bus"/>
      </Tab>
   </Page>
</Workspace>

training:EntityList.portlet

XML
<Portlet context="EntityId">
   <Script><![CDATA[(context-form-source (this'view) "EntityId" "training_EntityList_layout")]]></Script>
   <Composite name="composite">
      <LayoutRef association="training_EntityList_layout" layout="training:EntitySearch" name="training_EntitySearch_layout" query="true"/>
      <LayoutRef layout="training:EntityList" name="training_EntityList_layout"/>
   </Composite>
</Portlet>

training:EntitySearch.layout

XML
<Layout class="Entity">
   <Composite name="composite">
      <Filter name="filter"/>
   </Composite>
</Layout>

training:EntityList.layout

XML
<Layout class="Entity">
   <UIActions>
      <UIAction event="sysProperties">
         <Popup association="tblEntityList" edit="true" screen="training:mda:EntityProperties"/>
      </UIAction>
      <UIAction event="trainingShowSelection">
         <Script><![CDATA[(logger'info ((@ model)'multipleSelection))
(@ confirm : (format "{0} items selected." ((@ model)'multipleSelectionCount)))]]></Script>
      </UIAction>
   </UIActions>
   <Composite name="composite">
      <Table name="tblEntityList" order="lastName" permanent="3" rows="(@)" switch="filter searchContext value">
         <Menu name="mnuRightClick">
            <Item caption="ids.edit2" event="sysProperties" icon="edit" name="mitProperties"/>
            <Item event="sysRemove" name="deleteItem"/>
         </Menu>
         <SelectionMenu name="mnuMultiSelect">
            <Item event="trainingShowSelection" name="mnuMulti"/>
         </SelectionMenu>
         <Column caption="idsa.training.layout.EntityList.type" icons="type iconDefault" name="colType"/>
         <Column caption="idsa.training.layout.EntityList.icon" icons="(image . image)(data . mimeData)(type . mimeType)" name="colIcon" texts="initial"/>
         <Column caption="idsa.training.layout.EntityList.name" event="sysDetail" length="100" name="colName" customizable="#f" values="fullName" visible="#t"/>
         <Column caption="ids.Email" case="PSN" name="colPEmail" sortable="false" values="email fullAddress"/>
         <Column caption="ids.phoneNumber" case="PSN" length="20" name="colPAddress" sortable="false" values="workPhone fullAddress"/>
         <Column caption="ids.company" case="PSN" name="colFullCompany" values="companyName"/>
         <Column caption="ids.caption.lastUpdated" case="PSN" name="colPLastUpdated" values="editTime"/>
         <Column caption="IDS_LANGUAGE" case="PSN" name="colPLang" values="defaultLang caption"/>
         <Column caption="ids.city" case="CO" name="colBranch" values="defaultAddress city"/>
         <Column caption="IDS_TELEPHONE" case="CO" name="colCompAddress" sortable="false" values="workPhone fullAddress"/>
         <Column caption="ids.caption.lastUpdated" case="CO" name="colCompLastUpdated" values="editTime"/>
         <Column caption="ids.caption.lastUpdated" case="USR" name="colULastUpdated" values="editTime"/>
      </Table>
   </Composite>
</Layout>

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>

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>

training:mda:EntityProperties.dialog

XML
<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>

training:UIEvents.uievent

XML
<UIEvents>
   <UIEvent caption="idsa.training.uievents.UIEvents.showSelection" icon="icon:select" name="trainingShowSelection" tooltip="idsa.training.uievents.UIEvents.showSelection"/>
</UIEvents>

idsa.training.en.strings

XML
idsa.training.layout.EntityDetail.caption=Entity Detail
idsa.training.layout.EntityList.caption=Entity List
idsa.training.layout.EntityList.icon=Icon
idsa.training.layout.EntityList.name=Name
idsa.training.layout.EntityList.type=Type
idsa.training.portal.Contact.caption=My Training Application
idsa.training.uievents.UIEvents.showSelection=Show Selection
idsa.training.workspace.Sandbox.caption=Sandbox

Detail page structure

Our current simple page definition in training:Sandbox.workspace has one tab containing two portlets; our entityDetail portlet and the AFL app/bus portlet. The following:

training:Sandbox.workspace

XML
...
   <Page name="page">
      <Tab caption="IDS_DETAIL" layout="cols:3 fluid:true" name="tabDetail" type="grid">
         <PortletRef name="training_EntityDetail_portlet" portlet="training:EntityDetail"/>
         <PortletRef name="aflBus" portlet="app/bus"/>
      </Tab>
   </Page>
...

renders as:

One tab, two portlets

Learning activity

To add a page with more details:

  1. Replace the page definition in your training:Sandbox.workspace with the following source code:

    training:Sandbox.workspace

    XML
    <Workspace caption="idsa.training.workspace.Sandbox.caption" icon="icon:attach_money">
       <Navigator name="training_EntityList_portlet" portlet="training:EntityList"/>
       <Page name="pgContactDetail">
          <Banner name="mda_EntityDashboard_portlet" portlet="mda:EntityDashboard"/>
          <Tab caption="ids.fins.summary" layout="cols:3 fluid:true" name="tabSummary" type="grid">
             <PortletRef name="mda_EntityBio_portlet" portlet="mda:EntityBio"/>
             <PortletRef name="mda_ChartActivitiesByEntityPieChart_portlet" portlet="mda:ChartActivitiesByEntityPieChart"/>
             <PortletRef name="mda_EntityNotes_portlet" portlet="mda:EntityNotes"/>
             <PortletRef name="mda_EntitySummaryActivities_portlet" portlet="mda:EntitySummaryActivities"/>
          </Tab>
          <Tab caption="ids.activities" layout="cols:3 fluid:true" name="tabPersonJournal" type="grid">
             <PortletRef name="mda_EntityActivities_portlet" portlet="mda:EntityActivities"/>
          </Tab>
       </Page>
    </Workspace>
  2. Save, re-seed and refresh your browser. When you click on a name in the navigator, your UI should look similar to this:.

    Detail page with banner


    This is a better detail page. It has a banner control across the top as defined with the following source code:

    XML
          <Banner name="mda_EntityDashboard_portlet" portlet="mda:EntityDashboard"/>

    Two tabs of detail content

    Summary and Activities tabs
    as defined with the following source code:

    XML
    ...
          <Tab caption="ids.fins.summary" layout="cols:3 fluid:true" name="tabSummary" type="grid">
    ...
          <Tab caption="ids.activities" layout="cols:3 fluid:true" name="tabPersonJournal" type="grid">
    ...

    and a collection of PortletRefs that determine the portlets that show up on the tabs.


At this point, if you click on a Person, Company, or User you will get the same page. We can display different pages by type by using the page's case property, which is the name of class that this detail page is capable of displaying.

Learning activity

To add cases for Person, Company, and User:

  1. Replace the contents of training:Sandbox.workspace with the following code:

    training:Sandbox.workspace

    XML
    <Workspace caption="idsa.training.workspace.Sandbox.caption" icon="icon:attach_money">
       <Navigator name="training_EntityList_portlet" portlet="training:EntityList"/>
       <Page case="UserPerson" name="pgUserDetail">
          <Banner name="usr_mda_EntityDashboard_portlet" portlet="mda:EntityDashboard"/>
          <Tab caption="ids.fins.summary" layout="cols:3 fluid:true" name="tabUsrSummary" type="grid">
             <PortletRef name="usr_mda_EntityNotes_portlet" portlet="mda:EntityNotes"/>
             <PortletRef name="usr_mda_EntitySummaryActivities_portlet" portlet="mda:EntitySummaryActivities"/>
          </Tab>
          <Tab caption="IDS_DETAIL" layout="cols:3 fluid:true" name="tabOrgDetail" type="grid">
             <PortletRef name="usr_mda_ChartActivitiesByEntityPieChart_portlet" portlet="mda:ChartActivitiesByEntityPieChart"/>
          </Tab>
      </Page>
       <Page case="Person" name="pgContactDetail">
          <Banner name="psn_mda_EntityDashboard_portlet" portlet="mda:EntityDashboard"/>
          <Tab caption="ids.fins.summary" layout="cols:3 fluid:true" name="tabPsnSummary" type="grid">
             <PortletRef name="psn_mda_EntityBio_portlet" portlet="mda:EntityBio"/>
             <PortletRef name="psn_mda_ChartActivitiesByEntityPieChart_portlet" portlet="mda:ChartActivitiesByEntityPieChart"/>
             <PortletRef name="psn_mda_EntityNotes_portlet" portlet="mda:EntityNotes"/>
             <PortletRef name="psn_mda_EntitySummaryActivities_portlet" portlet="mda:EntitySummaryActivities"/>
          </Tab>
          <Tab caption="ids.activities" layout="cols:3 fluid:true" name="tabPersonJournal" type="grid">
             <PortletRef name="psn_mda_EntityActivities_portlet" portlet="mda:EntityActivities"/>
          </Tab>
       </Page>
       <Page case="Organization" name="pgOrganizationDetail">
          <Banner name="org_mda_EntityDashboard_portlet" portlet="mda:EntityDashboard"/>
          <Tab caption="ids.fins.summary" layout="cols:3 fluid:true" name="tabOrgSummary" type="grid">
             <PortletRef name="org_mda_ChartActivitiesByEntityPieChart_portlet" portlet="mda:ChartActivitiesByEntityPieChart"/>
             <PortletRef name="org_mda_EntityNotes_portlet" portlet="mda:EntityNotes"/>
             <PortletRef name="org_mda_EntitySummaryActivities_portlet" portlet="mda:EntitySummaryActivities"/>
          </Tab>
          <Tab caption="IDS_DETAIL" layout="cols:3 fluid:true" name="tabOrgDetail" type="grid">
             <PortletRef name="org_mda_EntityAddresses_portlet" portlet="mda:EntityAddresses"/>
             <PortletRef name="org_mda_EntityCustomFields_portlet" portlet="mda:EntityCustomFields"/>
             <PortletRef name="org_mda_EntityCommunications_portlet" portlet="mda:EntityCommunications"/>
          </Tab>
       </Page>
    </Workspace>
  2. Save, re-seed and refresh your browser.
    When you click on a name in the navigator, what you see depends on the type of item you've selected. The key here is the case="..." property on the pages. The page that displays is selected based on the page's case property matching the class of the selected item.


The name property of the portlet refs should be unique within the page. This is to allow automated testing tools to find the right location. A good standard is to prefix the name with some representation of the case property (here org, usr, or psn), replace : with _ in the portlet's name, and prefix with _portlet, so the mda:EntityAddresses portlet in the Organization page would have a name of org_mda_EntityAddresses_portlet.

Page selection and the case property

The first page that matches the current item's class is displayed. If no match is found, the last page in the list is used. Since the match is from top to bottom, you should place the most specific case in a class hierarchy at the top. For example, if there is a special page for UserPerson, this page should be placed above the Person page as it is more specific. Otherwise, the search matches on Person and uses that page, never reaching the UserPerson page because UserPerson is a subclass of Person.

That's about it for navigator pattern detail pages. The different types of portlets are discussed in the portlet patterns lessons.


JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.