Follow by Email

Saturday, 27 July 2013

Implementing master/detail tree relation using af:Iterator and af:forEach for better UI designs - Oracle ADF

In ADF Faces tree and tree table is used for hierarchical representation of master/detail form of data,
in this tutorial i will show you that how can we design better UI's using master detail data.
af:iterator and af:ForEach both are used to iterate data as af:table for custom UI component-

here i am taking example of default HR Schema of Oracle database , Departments and Employees table to show master-detail relation

Using af:iterator-

  • Create a Fusion Web Application and prepare model for master detail relationship between departments and employees table, and in your page drop af:showDetailHeader from component palette
  • Go to page binding, add tree binding for Departments (Master) and Employees (Detail)

  • Surround showDetailHeader with an af:iterator,  and set value and var for iterator (master)

  •  Now change text of showDetailHeader to show department name on it, taking reference from iterator's var

  • master part is done, for detail part  drop two output text (for employee's first name and last name) inside showDetailHeader surrounding with an iterator (for detail part)

  • set the value and var for detail iterator taking reference from master iterator 

  • Now to show detail values in output text , set the value in both output text, taking reference from detail iterator

  • See the source of page for more clarification-

  • <af:iterator id="i3" value="#{bindings.Departments1.collectionModel}" var="departments">
                                    <af:showDetailHeader text="#{departments.DepartmentName}" disclosed="true" id="sdh1"
                                        <f:facet name="context"/>
                                        <f:facet name="menuBar"/>
                                        <f:facet name="toolbar"/>
                                        <f:facet name="legend"/>
                                        <f:facet name="info"/>
                                        <af:panelGroupLayout id="pgl2" layout="vertical">
                                            <af:iterator id="i2" var="emp" value="#{departments.Employees}">
                                                <af:separator id="s3"/>
                                                <af:panelFormLayout id="pfl1" rows="1">
                                                    <af:outputText value="#{emp.FirstName}" id="ot2"
                                                    <af:outputText value="#{emp.LastName}" id="ot3"
                                                <af:spacer width="10" height="10" id="s1"/>

  • Now Run your page to see UI of this master-detail relationship-

Using af:ForEach-

  •  Drop a panel accordion on page, by default it has one af:showDetailItem , surround it with af:ForEach and set items and var for ForEach

  • change text of showDetailItem to show department name on it, taking reference from ForEach's var 

  • Now drop Employees detail table from data control inside showDetailItem and set its value , taking reference from ForEach 

  • For more clarification see source of page-

  • <af:panelAccordion id="pa1" styleClass="AFStretchWidth" visible="true">
                                    <af:forEach items="#{bindings.Departments1.children}" var="dept">
                                        <af:showDetailItem text="#{dept.DepartmentName}" id="sdi1" inflexibleHeight="200">
                                            <af:table value="#{dept.children}" var="row"
                                                      emptyText="#{bindings.Employees3.viewable ? 'No data to display.' : 'Access Denied.'}"
                                                      fetchSize="#{bindings.Employees3.rangeSize}" rowBandingInterval="0"
                                                      filterVisible="true" varStatus="vs"
                                                      rowSelection="single" id="t1" styleClass="AFStretchWidth">
                                                <af:column sortProperty="#{}"
                                                           filterable="true" sortable="false"
                                                    <af:outputText value="#{row.EmployeeId}"
                                                        <af:convertNumber groupingUsed="false"
                                                <af:column sortProperty="#{}"
                                                           filterable="true" sortable="false"
                                                    <af:outputText value="#{row.FirstName}"
                                                <af:column sortProperty="#{}"
                                                           filterable="true" sortable="false"
                                                           headerText="#{bindings.Employees3.hints.LastName.label}" id="c3">
                                                    <af:outputText value="#{row.LastName}"
                                                <af:column sortProperty="#{}"
                                                           filterable="true" sortable="false"
                                                           headerText="#{bindings.Employees3.hints.Email.label}" id="c4">
                                                    <af:outputText value="#{row.Email}"

  • Now run your page to see its UI-

Download Sample workspace here- Download
Happy Jdeveloping..


  1. Hi Ashish,

    Very nice blog, thanks for sharing this tip,

    I have one use case, can you please help me with that,

    I have Associations and view links between following entities in BC Layer:
    Department(Parent:1) and Employees (child: Many),
    Employees(Parent: 1) and Job history (child: Many).

    In JSFF:

    I have a form layout with two fields mapped from Department VO and then

    underneath it I have a iterator on Employees collection similar to the use case you provided here in first part of this blog and I surrounded showDetailHeader with the iterator (defined proper partial triggers on iterator for refreshing showDetailHeader area for inserting a new row in Employees via createinsert method from command image link and),

    now I have a requirement to show child table(Job history) data inside showDetailHeader: when I drag and drop the View Link(Job history) from data controls to jsff under the main iterator (for parent collection below Department form fields) & showDetailHeader it is not working as expected, Binding repeats for multiple parent rows.

    when I do create insert on parent(Employees) it shows blank rows in child table(Job history) for existing Employee rows,

    here we are dealing with Parent-->Child1(Association and VL between Parent and Child1 defined)
    -->Child2(Association and VL between Child1 and Child2)

    1. What if you call createInsert on a different viewObject instance and add values in a popup and then execute viewObject to reflect value in another instance ?