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"
                                                         inlineStyle="width:350px;">
                                        <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"
                                                                   inlineStyle="font-weight:bold;color:darkblue;"/>
                                                    <af:outputText value="#{emp.LastName}" id="ot3"
                                                                   inlineStyle="font-weight:bold;color:red;"/>
                                                </af:panelFormLayout>
                                                <af:spacer width="10" height="10" id="s1"/>
                                            </af:iterator>
                                        </af:panelGroupLayout>
                                    </af:showDetailHeader>
                                </af:iterator>
    

  • 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"
                                                      rows="#{bindings.Employees3.rangeSize}"
                                                      emptyText="#{bindings.Employees3.viewable ? 'No data to display.' : 'Access Denied.'}"
                                                      fetchSize="#{bindings.Employees3.rangeSize}" rowBandingInterval="0"
                                                      filterModel="#{bindings.Employees3Query.queryDescriptor}"
                                                      queryListener="#{bindings.Employees3Query.processQuery}"
                                                      filterVisible="true" varStatus="vs"
                                                      selectedRowKeys="#{bindings.Employees3.collectionModel.selectedRow}"
                                                      selectionListener="#{bindings.Employees3.collectionModel.makeCurrent}"
                                                      rowSelection="single" id="t1" styleClass="AFStretchWidth">
                                                <af:column sortProperty="#{bindings.Employees3.hints.EmployeeId.name}"
                                                           filterable="true" sortable="false"
                                                           headerText="#{bindings.Employees3.hints.EmployeeId.label}"
                                                           id="c1">
                                                    <af:outputText value="#{row.EmployeeId}"
                                                                   shortDesc="#{bindings.Employees3.hints.EmployeeId.tooltip}"
                                                                   id="ot4">
                                                        <af:convertNumber groupingUsed="false"
                                                                          pattern="#{bindings.Employees3.hints.EmployeeId.format}"/>
                                                    </af:outputText>
                                                </af:column>
                                                <af:column sortProperty="#{bindings.Employees3.hints.FirstName.name}"
                                                           filterable="true" sortable="false"
                                                           headerText="#{bindings.Employees3.hints.FirstName.label}"
                                                           id="c2">
                                                    <af:outputText value="#{row.FirstName}"
                                                                   shortDesc="#{bindings.Employees3.hints.FirstName.tooltip}"
                                                                   id="ot5"/>
                                                </af:column>
                                                <af:column sortProperty="#{bindings.Employees3.hints.LastName.name}"
                                                           filterable="true" sortable="false"
                                                           headerText="#{bindings.Employees3.hints.LastName.label}" id="c3">
                                                    <af:outputText value="#{row.LastName}"
                                                                   shortDesc="#{bindings.Employees3.hints.LastName.tooltip}"
                                                                   id="ot6"/>
                                                </af:column>
                                                <af:column sortProperty="#{bindings.Employees3.hints.Email.name}"
                                                           filterable="true" sortable="false"
                                                           headerText="#{bindings.Employees3.hints.Email.label}" id="c4">
                                                    <af:outputText value="#{row.Email}"
                                                                   shortDesc="#{bindings.Employees3.hints.Email.tooltip}"
                                                                   id="ot7"/>
                                                </af:column>
                                            </af:table>
                                        </af:showDetailItem>
                                    </af:forEach>
                                </af:panelAccordion>
    


  • Now run your page to see its UI-


Download Sample workspace here- Download
Happy Jdeveloping..

2 comments :

  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)

    ReplyDelete
    Replies
    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 ?

      Delete