2009年4月17日星期五

ADF 11g Multiple RowSelect on RichTable

在实际应用中,经常遇到需要在表格中选定一条或多条记录进行操作的情况。
  1. 使用ADF RichTable提供的Multiple RowSelect功能

  2. 在RichTable中增加列,使用基于VO的Checkbox进行RichTable的行多选

  3. 在RichTable中增加列,不基于VO进行RichTable的行多选

下面将详述三种实现方式,使用Oracle JDeveloper 11.1.1.0.1,数据源使用OracleXE版本中HR示例数据的Employees表,创建页面时默认绑定backingbean。

1.使用ADF RichTable提供的Multiple RowSelect
优点:RichTable原生支持,稳定快速,代码简单
缺点:只能按住键盘Ctrl键或Shift键通过鼠标进行多选,用户操作不直观
步骤:设置RichTable的属性,将RowSelection设为multiple,并将SelectedRowKeys设为空,即可在后台通过如下代码获得选定行的RowKey,进而可以通过在VO上通过对应RowKey得到对应行。

    public Boolean getIsChecked() {
//return (Boolean) getAttributeInternal(ISCHECKED);
return getAttributeInternal(ISCHECKED) == null ? false :
(Boolean)getAttributeInternal(ISCHECKED);
}


补充:为什么将SelectedRowKeys置为空
修改之前SelectedRowKeys值为#{bindings.EmployeesVO1.collectionModel.selectedRow},该EL表达式表明之前该Table的SelectedRowKeys绑定到了对应VO的selectedRow,但client端的状态改变并不能实时的提交到Server端,以至于当此绑定存在时,取到的是Server端存储的selectedRow而非client端当前的selectedrow。
2.在RichTable中增加列,使用基于VO的Checkbox进行RichTable的行多选
优点:使用checkbox的方式提供选择,代码复杂度中等
缺点:必须修改每一个需要使用该多选方式的RichTable对应的VO
步骤:
  1. 在VO添加非数据库项IsChecked,设置其Type为Boolean,Updateable为Always


  2. 为该VO生成ViewRowImpl.java,并修改IsChecked的get方法

        public Boolean getIsChecked() {
    //return (Boolean) getAttributeInternal(ISCHECKED);
    return getAttributeInternal(ISCHECKED) == null ? false :
    (Boolean)getAttributeInternal(ISCHECKED);
    }


  3. 将VO拖入页面创建RichTable,修改IsChecked列,将标签改为<af:selectBooleanCheckbox>,并将其Autosubmit/Immediate属性设为true,并在header中拖入另一个SelectBooleanCheckbox


  4. header里的Checkbox不能添加ValueChangeListener,如果已经添加,需要将ValueChangeListener重置为Default(空)。为Header里的Checkbox创建ClientListener和ServerListener,分别设置属性如下:
    ClientListener
    method: mainClientCall
    type: click

    ServerListener
    method: callMBmainmethod
    type: onSelectedOrDeselected()

    完成后如下





  5. 在页面转入Source模式,在标签 <af:document... <af:messages... 间加入如下代码

          <script type="text/javascript">
    <![CDATA[function mainClientCall (event)
    {
    var currcheckbox = event.getSource();
    var selectstatus = currcheckbox.getValue();
    //call method in manage bean
    AdfCustomEvent.queue(currcheckbox, "callMBmainmethod",{params:selectstatus}, true);
    }
    ]]>
    </script>




  6. 在页面backingbean中修改onSelectedOrDeselected方法,添加以下代码以实现全选功能。注意修改this.getTable()为你的目标表。
        public void onSelectedOrDeselected(ClientEvent clientEvent) {
    boolean isSelected =
    (Boolean)clientEvent.getParameters().get("params");
    RichTable rt = this.getTable1();
    for (int i = 0; i < rt.getRowCount(); i++) {
    JUCtrlHierNodeBinding rowData =
    (JUCtrlHierNodeBinding)rt.getRowData(i);
    Row row = rowData.getRow();
    if (isSelected) {
    row.setAttribute("IsChecked", true);
    } else {
    row.setAttribute("IsChecked", false);
    }
    }
    // Refresh target table state
    AdfFacesContext adfContext = AdfFacesContext.getCurrentInstance();
    UIComponent refreshComponent = this.getTable1();
    if (refreshComponent != null) {
    adfContext.addPartialTarget(refreshComponent);
    }
    }


  7. 可以在AppModel或ManageBean中通过遍历VO判断IsChecked的状态来取出选定行。


3.在RichTable中增加列,不基于VO进行RichTable的行多选
优点:使用checkbox的方式提供选择,
不必修改VO
缺点:
代码复杂度较高
步骤:

  1. RichTable中插入列,设置宽度(width)为13RowHeader属性为trueAlign属性为Center;在列及列header中分别拖入SelectBooleanCheckBox,设置checkboxsimple属性为true,删除其Text属性中的值。将全选checkboxID设置为maincheckbox,单选的checkbox
    ID
    设置为subcheckbox:(参考2.3)

  2. 分别为两个Checkbox创建一组ClientListener/ServerListener,属性设置如下(参考2.4)
    MainCheckbox
    clientListener
    Method: mainClientCall
    Type: click
    serverListener
    Type: callMBmainmethod
    Method: mainCheckBoxChecked()
    SubCheckbox
    clientListener
    Method: subClientCall
    Type: click
    serverListener
    Type: callMBsubmethod
    Method: subCheckBoxChecked()


  3. 在页面转入source模式,复制如下代码至<af: document ...<af: messages ...标签之间(参考2.5)
          <script type="text/javascript">
    <![CDATA[function mainClientCall (event)
    {
    var currcheckbox = event.getSource();
    var selectstatus = currcheckbox.getValue();

    //call method in manage bean
    AdfCustomEvent.queue(currcheckbox, "callMBmainmethod",{params:selectstatus}, true);
    }
    function subClientCall (event)
    {
    var currcheckbox = event.getSource();
    var selectstatus = currcheckbox.getValue();

    //call method in manage bean
    AdfCustomEvent.queue(currcheckbox, "callMBsubmethod",{params:selectstatus}, true);
    }
    ]]>
    </script>


  4. 修改页面对应Manage
    bean
    中的方法,修改mainCheckBoxChecked()subCheckBoxChecked()方法,添加如下代码
        public void getSelectedRows(ActionEvent actionEvent) {
    System.out.println("Selected Rows"); //debug
    System.out.println("******************************************"); //debug
    RowKeySet selectedRowsList = this.getMultipleCheckBoxProcess().getSelectedRowsList(this.getResId1());
    if (selectedRowsList != null && selectedRowsList.size() != 0) {
    for (Object temp : selectedRowsList)
    System.out.println("Get Row : " + temp);
    }
    System.out.println("******************************************"); //debug
    }
    public void CleanUpStatus(ActionEvent actionEvent) {
    this.getMultipleCheckBoxProcess().CleanUpStatus(this.getResId1(), "maincheckbox", "subcheckbox");
    }
    public void mainCheckBoxChecked(ClientEvent clientEvent) {
    Boolean currstatus = (Boolean)clientEvent.getParameters().get("params");
    this.getMultipleCheckBoxProcess().mainCheckBoxChecked(this.getResId1(), "subcheckbox", currstatus);
    }
    public void subCheckBoxChecked(ClientEvent clientEvent) {
    Boolean currstatus = (Boolean)clientEvent.getParameters().get("params");
    this.getMultipleCheckBoxProcess().subCheckBoxChecked(this.getResId1(), currstatus);
    }
    public MultipleCheckBox getMultipleCheckBoxProcess(){
    FacesContext ctx = FacesContext.getCurrentInstance();
    Application app = ctx.getApplication();

    MultipleCheckBox curr = (MultipleCheckBox)app.evaluateExpressionGet(ctx, "#{ viewScope.view_MultipleCheckbox}", Object.class);
    return curr;
    }


  5. 复制MultipleCheckbox.java至目标位置(在Demo中可以找到),在当前所使用的TaskFlow中添加Manage Bean名为view_MultipleCheckbox,Scope为view级别的Bean,指向MultipleCheckbox.java,修改MultipleCheckbox.java中的Package,使其与实际路径相符。


  6. 注意在适当的时候调用MultipleCheckbox的CleanUpStatus方法,一般在RichTable中数据发生改变时需要调用,如页面存在Query,则需在Query中调用MultipleCheckbox的CleanUpStatus方法。



补充:MultipleCheckBox中方法说明
  • public RowKeySet
    getSelectedRowsList(RichTable tartab);
    输入参数1:使用多选择CheckboxRichTable对象
    返回参数:选中的行的RowKey

  • public void setSelectedRowsList(RowKeySet
    selectedRowsList, RichTable tartab);
    输入参数1:选中行的RowKey
    输入参数2:使用多选择CheckboxRichTable对象

  • public void subCheckBoxChecked(RichTable
    tartab, Boolean checkStatus);
    输入参数1:使用多选择CheckboxRichTable对象
    输入参数2:当前Checkbox的状态
    该方法应在多Checkbox RichTable中某行前的Checkbox被选中/反选时调用

  • public void mainCheckBoxChecked(RichTable
    tartab, String subcheckboxid, Boolean newstatus);
    输入参数1:使用多选择CheckboxRichTable对象
    输入参数2:每行前Checkboxid
    输入参数3:当前全选Checkbox的状态
    该方法应在全选Checkbox被选中/反选时调用

  • public void CleanUpStatus(RichTable
    tartab, String maincheckboxid, String subcheckboxid);
    输入参数1:使用多选择CheckboxRichTable对象
    输入参数2:全选Checkboxid
    输入参数3:每行前Checkboxid
    该方法用于清除Checkbox的被选状态,通常需要执行查询前均需调用

Demo:
MultipleRowSelect1.rar

MultipleRowSelect2.rar

MultipleRowSelect3.rar

0 评论:

发表评论