Please disable your adblock and script blockers to view this page

Search this blog

Showing posts with label Tree. Show all posts
Showing posts with label Tree. Show all posts

Thursday, 16 April 2015

Build selectOneChoice to show hierarchical (tree style) data programmatically in ADF

This post is based on an old article from Frank Nimphius How - to build a select one choice displaying hierarchical selection data

This article is about showing tree structure data in af:selectOneChoice component using ADF BC , it makes use of tree binding and af:forEach
Same concept i have used to populate data from managed bean using List data structure

Let's see the implementation part - how to populate tree style selectOneChoice programatically ?

First we have to design a Java Bean class in such a way that it can hold  master -detail type of data

A class that represents a List for Parent Values
                          ======> A list of same type to hold Child Values

See bean class code-

import java.util.ArrayList;
import java.util.List;

public class Seasons {
    public Seasons(String name) {
        this.name = name; // To Store Header Values (Storing Seasons Name :))
    }
    // Season and Charater Name
    private String name;
    // To Store Detail Values (Storing Season's Charatcers)
    private List<Seasons> characters = new <Seasons>ArrayList();

    public void setCharacters(List<Seasons> empDet) {
        this.characters = empDet;
    }

    public List<Seasons> getCharacters() {
        return characters;
    }


    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
    // This methods directly add characters value in list
    public void addCharaters(Seasons employee) {
        characters.add(employee);
    }
}

Now how to use this bean in managed bean to add records, i have written code in constructor to populate values on class load




    // Master List to populate data in selectOnce choice
    List<Seasons> seasonList = new ArrayList<Seasons>();

    public void setSeasonList(List<Seasons> seasonList) {
        this.seasonList = seasonList;
    }

    public List<Seasons> getSeasonList() {
        return seasonList;
    }
    //Constructor of Managed Bean to populate data on page load (you can move this code )
    public TreeStyleLovBean() {
        super();
        // Creating tree for Seasons and Characters details
        // Adding Master Values (seasons)
        Seasons season1 = new Seasons("Game of Thrones");

        // Adding Detail Values (Child Node-Characters)
        Seasons character = new Seasons("Tywin Lannister");
        season1.addCharaters(character);
        character = new Seasons("Tyrion Lannister");
        season1.addCharaters(character);
        character = new Seasons("Jaime Lannister");
        season1.addCharaters(character);
        character = new Seasons("Cersie Lannister");
        season1.addCharaters(character);
        character = new Seasons("Ned Stark");
        season1.addCharaters(character);

        // Adding Master Values (seasons)
        Seasons season2 = new Seasons("Arrow");

        // Adding Detail Values (Child Node-Characters)
        character = new Seasons("Oliver Queen");
        season2.addCharaters(character);
        character = new Seasons("Moira Queen");
        season2.addCharaters(character);
        character = new Seasons("Laurel Lance");
        season2.addCharaters(character);
        character = new Seasons("Sara Lance");
        season2.addCharaters(character);

        // Adding Master Values (seasons)
        Seasons season3 = new Seasons("Vikings");

        // Adding Detail Values (Child Node-Characters)
        character = new Seasons("Ragnar Lothrak");
        season3.addCharaters(character);

        // Adding Master Values (seasons)
        Seasons season4 = new Seasons("The Flash");

        // Adding Detail Values (Child Node-Characters)
        character = new Seasons("Barry Allen");
        season4.addCharaters(character);
        character = new Seasons("Harisson Wells");
        season4.addCharaters(character);
        character = new Seasons("Iris West");
        season4.addCharaters(character);
        character = new Seasons("Joe");
        season4.addCharaters(character);

        // Adding all list to topList
        seasonList.add(season1);
        seasonList.add(season2);
        seasonList.add(season3);
        seasonList.add(season4);

    }
how to bind this managed bean to selectOneChoice ? i have used same concept as described in Frank's article using af:forEach


<af:selectOneChoice id="selectBox" label="Choose Character" valuePassThru="true"
                                        styleClass="employeeSelectBox" contentStyle="width:150px;"
                                        binding="#{viewScope.TreeStyleLovBean.selectOneValueBind}">
                        <af:forEach items="#{viewScope.TreeStyleLovBean.seasonList}" var="seasonNm">
                            <af:selectItem label="#{seasonNm.name}" disabled="true" id="si1"/>
                            <af:forEach items="#{seasonNm.characters}" var="characterNm">
                                <af:selectItem label="#{characterNm.name}" value="#{characterNm.name}" id="si2"/>
                            </af:forEach>
                        </af:forEach>
                    </af:selectOneChoice>

you can see here that first forEach is populated from master list and iterates over list of seasons and first selectItem show season's name
the inner forEach makes used of character list that is defined in Java Bean class and stores season wise character's name
Rest is same - a CSS is used to differentiate color and alignment of parent and child records (same as Frank's article)


<f:facet name="metaContainer">
                <af:group>
                    <![CDATA[
<style>
.employeeSelectBox option{text-indent:15px;color:darkgreen;}
.employeeSelectBox option[disabled]{color:red; background-color:#dddddd; 
font-weight: bold; text-indent:0px}
</style>
]]>
                </af:group>
            </f:facet>

Now run this application - see how it appears on page



It looks quite good :) to get selected value in bean just use componentBinding.getValue();

Sample ADF Application-Download (Jdev 12.1.3)
Cheers , Happy Learning 

Monday, 26 August 2013

Tree Table Component with declarative presentation in ADF, Access childs without custom selection listener

Hello all,
this is my second post on af:treeTable, first post was about creating and overriding tree table selection listener to get node value in managed bean, see
Tree Table Component in Oracle ADF(Hierarchical Representation)

In this post i am going to explain how to
  • use multiple detail column in treeTable
  • design better UI
  • manage child rows
  • use link,image,checkbox in treeTable conditionally
so i assume that you all know about creating treeTable, i am using default HR Schema (Employees ,Departments table) to master detail relation in tree and i have to show detail of Employee under Department node
  • I have created a treeTable using following details of Employees VO
  • Now on running my page it is looking like this, very odd and complex view
        xml source-

  <af:treeTable value="#{bindings.Departments1.treeModel}" var="node"
                              selectionListener="#{bindings.Departments1.treeModel.makeCurrent}" rowSelection="single"
                              id="tt1">
                    <f:facet name="nodeStamp">
                        <af:column id="c1" width="500">
                            <af:outputText value="#{node}" id="ot1"/>
                        </af:column>
                    </f:facet>
                    <f:facet name="pathStamp">
                        <af:outputText value="#{node}" id="ot2"/>
                    </f:facet>
                </af:treeTable>

  • It shows that all details of employees are clubbed in one column that is nodestamp, now to show details in different columns i have added 5 columns in treeTable, and seperate detail in each column as Email, FirstName,LastName etc
    To add column right click on treeTable and insert-
 In column drop an input text and set its value taking node reference




  •  Now run page and see, there is now 5 column with different details but still that clubbed value is shown.
  • Now to remove that clubbed detail, go to nodestamp facet of treeTable and see value of output text inside column, it is set to #{node} ,due to this all values available in node are clubbed and displayed in page, now we have to set its value to any of Master table's (Departments) attribute



  •  Now run page , only department name is displayed on header, and corresponding value for detail is blank
  •  We are done with this part, now try to make its UI somewhat better using some styles, so i have used different background color for header and detail part of treeTable conditionally
  • To do this i have set inline style property conditionally , because i have to change color of same column according to master and detail data, see condition

  • #{node.DepartmentName!=null ? 'background-color:darkgreen' :  'background-color:rgb(239,255,213);'  }
    

  • Now see how to get selected child row without over-riding treeTable's selection listener, to do this i have added a image link in treeTable and created a action listener on that to show current selected detail row
  • Bind tree table to managed bean and create two methods to get selected RowIterator and node Key

  •     /**Tree Table Binding in managed bean*/
        private RichTreeTable treeTabBind;
    
        public void setTreeTabBind(RichTreeTable treeTabBind) {
            this.treeTabBind = treeTabBind;
        }
    
        public RichTreeTable getTreeTabBind() {
            return treeTabBind;
        }
    
        /**Method to get Iterator*/
        public RowIterator getSelectedNodeIterator() {
            if (getTreeTabBind() != null && getTreeTabBind().getSelectedRowKeys() != null) {
                for (Object rKey : getTreeTabBind().getSelectedRowKeys()) {
                    getTreeTabBind().setRowKey(rKey);
                    return ((JUCtrlHierNodeBinding)getTreeTabBind().getRowData()).getRowIterator();
                }
            }
            return null;
        }
    
        /**Method to get Node Key*/
        public Key getSelectedNodeKey() {
            if (getTreeTabBind() != null && getTreeTabBind().getSelectedRowKeys() != null) {
                for (Object rKey : getTreeTabBind().getSelectedRowKeys()) {
                    getTreeTabBind().setRowKey(rKey);
                    return ((JUCtrlHierNodeBinding)getTreeTabBind().getRowData()).getRowKey();
                }
            }
            return null;
        }
    

  • Now to get currently selected node and row pass Iterator and Node key in this method- see

  •     public void showCurRowDetail(RowIterator ri, Key selectedNodeKey) {
            Row[] rows = ri.findByKey(selectedNodeKey, 1);
    
            FacesMessage msg = new FacesMessage(rows[0].getAttribute("FirstName") + "'s data available in this row");
            FacesContext.getCurrentInstance().addMessage(null, msg);
        }
    

  • Now Run application and click on link to see selected row -