Undo row selection of af:table in selection listener method conditionally

Sharing is Caring

Recently I have seen a question on OTN JDeveloper forum and It was about table selection listener
The requirement is like this suppose the user has to check a condition after selecting a row and if that condition is true only then the new row will be selected else selected row should be the previous one

It means undo row selection on validation(condition) failure
So In this post, I am implementing the same scenario and here I am using Departments table of HR Schema to prepare model and condition is that user should be able to select new row only if ManagerId is not null

Drop Departments view object on page as af:table and create a custom selection listener in the managed bean

<af:table value="#{bindings.DepartmentsVO1.collectionModel}" var="row"
                          rows="#{bindings.DepartmentsVO1.rangeSize}"
                          emptyText="#{bindings.DepartmentsVO1.viewable ? 'No data to display.' : 'Access Denied.'}"
                          rowBandingInterval="0"
                          selectedRowKeys="#{bindings.DepartmentsVO1.collectionModel.selectedRow}" rowSelection="single"
                          fetchSize="#{bindings.DepartmentsVO1.rangeSize}"
                          filterModel="#{bindings.DepartmentsVO1Query.queryDescriptor}"
                          queryListener="#{bindings.DepartmentsVO1Query.processQuery}" filterVisible="true"
                          varStatus="vs" id="t1" autoHeightRows="10" styleClass="AFStretchWidth"
                          contentDelivery="immediate"
                          selectionListener="#{viewScope.TableSelectionBean.tableSelectionListener}">
                    <af:column sortProperty="#{bindings.DepartmentsVO1.hints.DepartmentId.name}" filterable="true"
                               sortable="true" headerText="#{bindings.DepartmentsVO1.hints.DepartmentId.label}" id="c1">
                        <af:outputText value="#{row.DepartmentId}"
                                       shortDesc="#{bindings.DepartmentsVO1.hints.DepartmentId.tooltip}" id="ot1">
                            <af:convertNumber groupingUsed="false"
                                              pattern="#{bindings.DepartmentsVO1.hints.DepartmentId.format}"/>
                        </af:outputText>
                    </af:column>
                    <af:column sortProperty="#{bindings.DepartmentsVO1.hints.DepartmentName.name}" filterable="true"
                               sortable="true" headerText="#{bindings.DepartmentsVO1.hints.DepartmentName.label}"
                               id="c2">
                        <af:outputText value="#{row.DepartmentName}"
                                       shortDesc="#{bindings.DepartmentsVO1.hints.DepartmentName.tooltip}" id="ot2"/>
                    </af:column>
                    <af:column sortProperty="#{bindings.DepartmentsVO1.hints.ManagerId.name}" filterable="true"
                               sortable="true" headerText="#{bindings.DepartmentsVO1.hints.ManagerId.label}" id="c3">
                        <af:outputText value="#{row.ManagerId}"
                                       shortDesc="#{bindings.DepartmentsVO1.hints.ManagerId.tooltip}" id="ot3">
                            <af:convertNumber groupingUsed="false"
                                              pattern="#{bindings.DepartmentsVO1.hints.ManagerId.format}"/>
                        </af:outputText>
                    </af:column>
                    <af:column sortProperty="#{bindings.DepartmentsVO1.hints.LocationId.name}" filterable="true"
                               sortable="true" headerText="#{bindings.DepartmentsVO1.hints.LocationId.label}" id="c4">
                        <af:outputText value="#{row.LocationId}"
                                       shortDesc="#{bindings.DepartmentsVO1.hints.LocationId.tooltip}" id="ot4">
                            <af:convertNumber groupingUsed="false"
                                              pattern="#{bindings.DepartmentsVO1.hints.LocationId.format}"/>
                        </af:outputText>
                    </af:column>
                </af:table>

Now next step is implementing SelectionListener code so for that logic is simple

  • First We need to get currently selected row key (Old Row)
  • Set newly selected row as the current row
  • Now get current row (new row) and check that ManagerId should not be null
  • If it is null then set the previous row as the current row

Packages Used

import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.MethodExpression;
import javax.el.ValueExpression;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;

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

import oracle.jbo.Row;

import org.apache.myfaces.trinidad.event.SelectionEvent;
import org.apache.myfaces.trinidad.model.RowKeySet;

Helper Methods

    /**
     * Programmatic invocation of a method that an EL evaluates to.
     * The method must not take any parameters.
     *
     * @param el EL of the method to invoke
     * @return Object that the method returns
     */
    public static Object invokeEL(String el) {
        return invokeEL(el, new Class[0], new Object[0]);
    }

/**
 * Programmatic invocation of a method that an EL evaluates to.
 *
 * @param el EL of the method to invoke
 * @param paramTypes Array of Class defining the types of the parameters
 * @param params Array of Object defining the values of the parametrs
 * @return Object that the method returns
 */
public static Object invokeEL(String el, Class[] paramTypes, Object[] params) {
FacesContext facesContext = FacesContext.getCurrentInstance();
ELContext elContext = facesContext.getELContext();
ExpressionFactory expressionFactory = facesContext.getApplication().getExpressionFactory();
MethodExpression exp = expressionFactory.createMethodExpression(elContext, el, Object.class, paramTypes);
return exp.invoke(elContext, params);
}

/**
 * Programmatic evaluation of EL.
 * @param el EL to evaluate
 * @return Result of the evaluation
 */
public static Object evaluateEL(String el) {
FacesContext facesContext = FacesContext.getCurrentInstance();
ELContext elContext = facesContext.getELContext();
ExpressionFactory expressionFactory = facesContext.getApplication().getExpressionFactory();
ValueExpression exp = expressionFactory.createValueExpression(elContext, el, Object.class);
return exp.getValue(elContext);
}

 

SelectionListener of af:table

    /**Method to invoke custom selection listener
     * @param selectionEvent
     */
    public void tableSelectionListener(SelectionEvent selectionEvent) {
        //Get previous selected row key
        RowKeySet oldRowKey = selectionEvent.getRemovedSet();
        //Get Richtable instance fron selectionEvent
        RichTable table = (RichTable) selectionEvent.getSource();
        //Invoke this EL to make selected row as current
        invokeEL("#{bindings.DepartmentsVO1.collectionModel.makeCurrent}", new Class[] { SelectionEvent.class }, new Object[] {
                 selectionEvent });
        // Get the selected row , by this you can get any attribute of that row
        Row selectedRow = (Row) evaluateEL("#{bindings.DepartmentsVO1Iterator.currentRow}");
        System.out.println("Selected Deaprtment is- " + selectedRow.getAttribute("DepartmentName"));
        //Now check condition that Manager Id should not be null for newly selected row
        if (selectedRow.getAttribute("ManagerId") == null) {
            //If Manager Id is null then set focus on previously selected row and show a message to user
            table.setSelectedRowKeys(oldRowKey);
            //Refresh table
            AdfFacesContext.getCurrentInstance().addPartialTarget(table);
            //Show FacesMessage
            FacesContext fctx = FacesContext.getCurrentInstance();
            fctx.addMessage(null, new FacesMessage("Can't Select new row as Manager Id is null"));
            //Save and render response
            fctx.renderResponse();
        }
    }

Now run and check application

Try to select a Department that has no manager

Undo row selection on selection listener


Cheers 🙂 Happy Learning

Related Posts

5 thoughts on “Undo row selection of af:table in selection listener method conditionally”

  1. Hello sir, I'm Chandan and I follow your blog and on Quora..The contents you post are very useful.
    After around two months of preparation I took 1z0-554 certification but I couldn't clear it.anyhow I'm again taking the exam.
    I've some set of questions which I'm trying to find answers that appeared in the exam.
    If possible please give me your mail id and I'll send the questions.if you give me the solutions for it, It'll be very useful..My mail id chandanhs77@gmail.com

  2. Nice post,thanks for giving this post this is very useful to every one and like this types also good explanation.thank you

Leave a Reply

Your email address will not be published. Required fields are marked *