Showing posts with label RichTable. Show all posts
Showing posts with label RichTable. Show all posts

Tuesday, January 5, 2010

EJB and ADF Faces RC: Inserting and Deleting Records to an Editable ADF Table that is Bound to an Entity (ArrayList) in a Managed Bean

My inspiration to write this post are the challenges that I have encountered in getting the selected row data, the method to remove rows and the inconsistent state of the table rows after removing a record. The Web User Interface Developers' Guide do not have a straight forward illustration on removing a row on a table that is not bound to an ADF Model/ADF BC type of data. Please note that I have not tried to run the codes below, but I have tried to demonstrate as much as possible the idea from the existing project that we have.

We have a requirement to have an editable master-detail information in which the master should be an editable form and the detail should be an editable table. This is a usual user-interface requirement for a accounting application especially on journal voucher entry screens (believe me here because I am a Certified Public Accountant :) ). In my encounter, the challenge was on the editable detail table. As much as possible I am sticking to the drag and drop from Data Controls panel style of creating the UI, but I cannot stick to it this time especially that this detail table has dependency on the master form (like "What's the applicable exchange rate defined in the master form?"- which is to be used by the rows of the detail table to translate an original currency Debits and Credits to base currency amounts) plus the fact that I need to conditionally set the visibility and required attribute of other components in the detail-table row based on the property of a selected account (an object on the same row).
Below is an illustrative code fragment to demonstrate the idea.
<af:panelCollection id="pc1">
  <f:facet name="toolbar">
    <af:toolbar id="t3">
      <af:commandToolbarButton text="Add"
                               id="ctb2"
                               actionListener="#{myBackingBean.addNewMyDetailObject}"/>
      <af:commandToolbarButton text="Remove"
                               id="ctb3"
                               actionListener="#{myBackingBean.removeSelectedMyDetailObject}"
                               immediate="true" />
    </af:toolbar>
  </f:facet>
  <af:table value="#{myBackingBean.myMasterObject.myDetailObjectList}"
                      var="row" id="t2"
                      partialTriggers="::ctb2 ::ctb3"
                      binding="#{myBackingBean.myDetailObjectRichTable}"
                      rowSelection="single"
                     
    <af:column sortable="false" headerText="Property 1" id="c1"
      <af:inputText value="#{row.myDetailObjectProperty1}" id="it1"/>
    </af:column>
      <af:column sortable="false" headerText="Property 2" id="c2"
    <af:inputText value="#{row.myDetailObjectProperty2}" id="it2"/>
      </af:column>
  </af:table>
</af:panelCollection>
I made a dummy backing bean class below to show the sample methods to insert and remove a row from the editable detail table:
package blogspot.soadev.view.backing;

import java.io.Serializable;

import java.util.List;

import javax.faces.event.ActionEvent;

import oracle.adf.view.rich.component.rich.data.RichTable;

public class MyBackingBean implements Serializable {
    private MyMasterObject myMasterObject;
    private RichTable myDetailObjectRichTable;
    
  public void addNewMyDetailObject(ActionEvent e) {
    MyDetailObject myDetailObject = new MyDetailObject();
    // add my deatil object to master
    myMasterObject.addMyDetailObject(myDetailObject);
    //can initialize myDetailObject properties if needed
    myDetailObject.setMyDetailObjectProperty1("property1 can be complex type");
    myDetailObject.setMyDetailObjectProperty2("property2 can be complex type");
  }
  public void removeSelectedMyDetailObject(ActionEvent e) {
    //get the selected row data
    MyDetailObject myDetailObject = (MyDetailObject)myDetailObjectRichTable.getSelectedRowData();
    //remove it from the master object
    myMasterObject.removeMyDetailObject(myDetailObject);
    //this my tip - refreshes the table stamping.
    //this is especilly needed if you conditionally set the attributes 
    //of other components (like visibility, rendered, required, etc)
    //if you will not invoke this, you will have inconsistent table row state.
    myDetailObjectRichTable.resetStampState();
  }


  public void setMyDetailObjectRichTable(RichTable myDetailObjectRichTable) {
    this.myDetailObjectRichTable = myDetailObjectRichTable;
  }

  public RichTable getMyDetailObjectRichTable() {
    return myDetailObjectRichTable;
  }

  public void setMyMasterObject(MyMasterObject myMasterObject) {
    this.myMasterObject = myMasterObject;
  }

  public MyMasterObject getMyMasterObject() {
    return myMasterObject;
  }
}

class MyDetailObject{
    private MyMasterObject myMasterObject;
    private Object myDetailObjectProperty1;
    private Object myDetailObjectProperty2;

  public void setMyMasterObject(MyMasterObject myMasterObject) {
    this.myMasterObject = myMasterObject;
  }

  public MyMasterObject getMyMasterObject() {
    return myMasterObject;
  }

  public void setMyDetailObjectProperty2(Object myDetailObjectProperty2) {
    this.myDetailObjectProperty2 = myDetailObjectProperty2;
  }

  public Object getMyDetailObjectProperty2() {
    return myDetailObjectProperty2;
  }

  public void setMyDetailObjectProperty1(Object myDetailObjectProperty1) {
    this.myDetailObjectProperty1 = myDetailObjectProperty1;
  }

  public Object getMyDetailObjectProperty1() {
    return myDetailObjectProperty1;
  }
}

class MyMasterObject{
    private List<MyDetailObject> myDetailObjectList;  
    public void addMyDetailObject(MyDetailObject myDetailObject){
          getMyDetailObjectList().add(myDetailObject);
          myDetailObject.setMyMasterObject(this);
    }
    public void removeMyDetailObject(MyDetailObject myDetailObject){
        getMyDetailObjectList().remove(myDetailObject);
        myDetailObject.setMyMasterObject(null);
    }

    public void setMyDetailObjectList(List<MyDetailObject> myDetailObjectList) {
      this.myDetailObjectList = myDetailObjectList;
    }

    public List<MyDetailObject> getMyDetailObjectList() {
      if(myDetailObjectList == null){
          myDetailObjectList = new ArrayList<MyDetailObject>();
      return myDetailObjectList;
    }
}
Please note of my tip on the table resetStampState() method above.
You maybe asking by now- "Where is the EJB part?", well, my master object is bound to an EJB DataControl ;) .