JDev: How to reset a filter on an af:table

In my last blog entry “How to reset or undo a af:table sort” I showed how to clear a sort on a column of an af:table.

Chris Muir asked me to do a follow up showing how to do the same for a filter an an af:table. A short research about this question did not turn up anything. If somebody already has bloged about this, please drop me note and I’ll mention you for reference.

************
OK, just 5 minutes after first publishing I found Steve Muenchs sample #146 at http://blogs.oracle.com/smuenchadf/resource/examples. More to come?
************

You can download a sample workspace, which was set up using JDeveloper 11.1.2.1.0 and the HR schema as DB connection, using the link at the end of the blog.

The use case for the blog is

  1. A use has a filterable af:table on a page. At some point he fills in one or more filter criteria and executes the query.
  2. Now he wants to clear the filter criteria to show all rows again.

Here is the code for a table with filtering enabled. As you see the filter is implemented as a filterModel (line 06: filterModel=”#{bindings.ImplicitViewCriteriaQuery.queryDescriptor}”).

                        <af:table value="#{bindings.EmployeesView1.collectionModel}" var="row"
                                  rows="#{bindings.EmployeesView1.rangeSize}"
                                  emptyText="#{bindings.EmployeesView1.viewable ? 'No data to display.' : 'Access Denied.'}"
                                  fetchSize="#{bindings.EmployeesView1.rangeSize}"
                                  rowBandingInterval="0"
                                  filterModel="#{bindings.ImplicitViewCriteriaQuery.queryDescriptor}"
                                  queryListener="#{bindings.ImplicitViewCriteriaQuery.processQuery}"
                                  filterVisible="true" varStatus="vs"
                                  selectedRowKeys="#{bindings.EmployeesView1.collectionModel.selectedRow}"
                                  selectionListener="#{bindings.EmployeesView1.collectionModel.makeCurrent}"
                                  rowSelection="single" id="resId1" styleClass="AFStretchWidth"
                                  binding="#{ResetTableFilterBean.empTable}"
                                  columnStretching="multiple">
                            <af:column sortProperty="#{bindings.EmployeesView1.hints.EmployeeId.name}"
                                       filterable="true" sortable="true"
                                       headerText="#{bindings.EmployeesView1.hints.EmployeeId.label}"
                                       id="resId1c1">

From the javadoc

getFilterModel

public final java.lang.Object getFilterModel()

    Gets the model used for filtering of data in the table. This attribute must be bound to an instance of FilterableQueryDescriptor class.

we see that the filterModel needs to be casted to a FilterableQueryDescriptor. A look into the javadoc shows that the class has a method to get a map of all criteria entered into the filter fields of a table. Here’s the javadoc for the FilterableQueryDescriptor.getFilterCriteria() method:

getFilterCriteria

public abstract java.util.Map<java.lang.String,java.lang.Object> getFilterCriteria()

    Gets the filter criteria associated with the query descriptor. Filter Criteria are generally useful for filtering data in the table.

    Returns:
        Map<String, Object> containg the filterCriteria

Clearing this map clears the filter fields of the table. Finally we queue an query event to the table to refresh it. Here is the bean code:

public class ResetTableFilterBean
{
    private RichTable empTable;

    public ResetTableFilterBean()
    {
    }

    public void resetTableFilter(ActionEvent actionEvent)
    {
        FilterableQueryDescriptor queryDescriptor =
            (FilterableQueryDescriptor) getEmpTable().getFilterModel();
        if (queryDescriptor != null && queryDescriptor.getFilterCriteria() != null)
        {
            queryDescriptor.getFilterCriteria().clear();
            getEmpTable().queueEvent(new QueryEvent(getEmpTable(), queryDescriptor));
        }
    }

    public void setEmpTable(RichTable empTable)
    {
        this.empTable = empTable;
    }

    public RichTable getEmpTable()
    {
        return empTable;
    }
}

In the following picture we see a page holding the query panel with a table with filter enabled. A search for employees with last name starting with ‘K’ has been executed and the result has been filtered for last name starts with ‘Ki’.

Query Panel with Filterable Table

Query Panel with Filterable Table

After a click an the ‘Reset Table Filter’ button clears the filter and shows the result for the query only.

Filter reset

Filter reset

The sample workspace uses JDeveloper 11.1.2.1.0 but the bean code should work in older JDeveloper version 11.1.1.x too. The sample used the HR schema as DB connection. You can download the sample workspace from BlogResetTableFilter.zip
After downloading the file rename it to ‘BlogResetTableFilter.zip’!

The sample also contains an other page showing the same for a simple table without the query panel.

Advertisements

JDev: How to reset or undo a af:table sort

This entry describes how to reset or undo a sort a user has initiated by clicking on a header in an af:table. The use case is based on a question on OTN Jdeveloper forum.
A more detailed description of the case is as follows:

  1. A use has a sortable af:table on a page. At some point he clicks the column header to sort the data.
  2. Now he wants to get back to the unsorted list which he gets is when the table is first shown.

The first part is easily accomplished by setting the sortable property of the columns of the table to true:

<af:table value="#{bindings.EmployeesView1.collectionModel}" var="row"
                          rows="#{bindings.EmployeesView1.rangeSize}"
                          emptyText="#{bindings.EmployeesView1.viewable ? 'No data to display.' : 'Access Denied.'}"
                          fetchSize="#{bindings.EmployeesView1.rangeSize}" rowBandingInterval="0"
                          selectedRowKeys="#{bindings.EmployeesView1.collectionModel.selectedRow}"
                          selectionListener="#{bindings.EmployeesView1.collectionModel.makeCurrent}"
                          rowSelection="single" id="resId1" styleClass="AFStretchWidth"
                          displayRow="selected" binding="#{RTSBean.qtable}">
                    <af:column sortProperty="#{bindings.EmployeesView1.hints.EmployeeId.name}"
                               sortable="true"
                               headerText="#{bindings.EmployeesView1.hints.EmployeeId.label}"
                               id="resId1c1">
...

Part 2 of the case isn’t obvious as there is no ‘unsort’ or ‘reset sort’ button available at design time. To undo the sort you have to do two things:

  1. remove the sort criteria from the table (this will remove the arrows in the column header)
  2. remove the sort criteria from the underlying iterator of the table and execute the query again (this gets the data unsorted from the DB)

Now that we know what to do let’s implement it. You’ll find a link to a working workspace at the end of the article.

public class RTSBean
{
    private RichTable qtable;

    public RTSBean()
    {
    }


    public void resetSort(ActionEvent actionEvent)
    {
        // get the binding container
        BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry();
        DCBindingContainer dcBindings = (DCBindingContainer) bindings;
        RichTable table = getQtable();
        table.queueEvent(new SortEvent(table, new ArrayList<SortCriterion>()));
        DCIteratorBinding iterBind = (DCIteratorBinding) dcBindings.get("EmployeesView1Iterator");
        Key currentRow = null;
        Row row = iterBind.getCurrentRow();
        if (row != null)
            currentRow = row.getKey();
        SortCriteria[] sc = new SortCriteria[0];
        iterBind.applySortCriteria(sc); // iterBind is the iterator the table uses
        iterBind.executeQuery();
        if (currentRow != null)
            iterBind.setCurrentRowWithKey(currentRow.toStringFormat(true));
    }

    public void setQtable(RichTable qtable)
    {
        this.qtable = qtable;
    }

    public RichTable getQtable()
    {
        return qtable;
    }
}

I’m using the method resetSort(ActionEvent actionEvent) to do the work. I bound the table to a bean property to make it easily accessible in the method. You can also search for the table component in the component tree (using the id of the table) if you like.
The method first queues a new sort event to the table with an empty list of sort criterion. This removes the sort arrows from the column header. Next it gets the iterator which is used by the table and saves its current row. I do this to re-select the row after I executed the query again. This way the user still sees the selected row after the sort is reset. An empty array of sort criteria is created and applied to the iterator removing all sort criteria currently applied. The query of the iterator gets executed and finally the selected row is set again (if it was set before).

This successfully resets a table to unsorted mode. This picture show the table after an initial search (without criteria entered in the name field):

Unsortet table after first load

Unsortet table after first load

Next I sorted the ‘salary’ column and selected the Row with employee_id 162:

Sorted table with row 162 selected

Sorted table with row 162 selected

The final picture shows the table after a click on the ‘Reset Sort’ button:

Table after 'Reset Sort'

Table after 'Reset Sort'


As you see the row with ‘EmployeeId’ 162 is still selected and scrolled into first position as the table is set to displayRow=”selected”.

The sample workspace uses JDeveloper 11.1.2.1.0 but the bean code should work in older JDeveloper version 11.1.1.x too. The sample used the HR schema as DB connection.
You can download the sample workspace from BlogResetTableSort.zip
After downloading the file rename it to ‘BlogResetTableSort.zip’!

Disclaimer and Acknowledgment: I remember an old blog post by Frank Nimphius showing this too. However, I couldn’t find it on the web and decided to show how to do it again.

JDeveloper: Don’t overlook warning signs in task flows or check your ‘Show Warning’ settings

This week I came across a hard to find error using task flows, which was caused by a simple reason.

I tired out Frank Nimphius samples #52 about using task flows which are not part of the application itself, but which are added from adf libraries to the application. First I tried the sample Frank provided in the Code Corner article, which worked as expected after changing the db connections to my environment.

Running Sample #52

Running Sample #52

Next I’d build my own task flow in an adf library and tired to use it in the parent application as reagion. All went OK till I run the application. Here is the picture

My application with Task Flow in Library

My application with Task Flow in Library

As you can see the region representing the task flow from the library is not shown or empty. The first step to analyze the error was to inspect the task flow in the library which looked like:

Rebuilded task flow in the adf library

Rebuilded task flow in the adf library

This looked OK for me and a further visual inspection of each of the other elements did not show any difference compared to Franks sample. Here are the images of the method call activity

Method call setdeptId

Method call setdeptId

and the navigation together with the navigation target

Navigation and target page

Navigation and target page

After some more checking I saw the hint which finally lead me to finding the error. In the image above you see a yellow or brownish frame around the ‘From Outcome’ field. I didn’t pay much attention to this at first, but after checking the ‘setdeptId’ method call outcome and the navigation targets ‘From Outcome’ I saw the difference.
The ‘setdeptId’ method call had ‘setdeptId’ set as ‘Fixed Outcome’ whereas the navigation was set to ‘goEmployees’. Once these two attributes are set to the same value the the color frame is gone.

Navigation target after correction

Navigation target after correction

Some questions still to answer:
(q1) Why don’t you get any error output in the log when running the application?
(q2) Why do you see no other error or warning in the design view in JDeveloper?

The answer to (q1) is easy once you found the reason for the error. As the method call activity (setting the department id and executing the query) did not throw an error, the navigation took place. As the outcome was set to not existing target, the region remains empty. A this could be desired behavior and no exception occurred no log output is generated.

Question (q2) took some more research. Lately I wrote a couple of blog entries with many pictures from the samples I used to show something. Some of of the images I used showed a small yellow attention sign when e.g. a page element on a task flow when the page is not created jet. As I took some of the images before the pages where ready and I didn’t want to show the warnings in my pictures, I turn the warnings off. This is not a problem as I later created the missing pages. But I forgot about this change with the result that the visual warning for the error I described here was hidden.
With the warning turned on again the error is easy to detect:

Task Flow in the library with 'Show Warnin' on

Task Flow in the library with 'Show Warnin' on

To turn the ‘Show Warning’ on or off you drop down the ‘Show’ list box in the diagram view of a task flow or page:

'Show Warnig'

'Show Warnig'

So, always remember to reset settings you only change for your convenience or make sure you never forget their impact.

Off Topic

image

image

image

As many of you are attending or following the OOW right now, I thought that I post a little contrast program I’m ‘attending’ currently.
No tech content, just fun. 
I’m spending a fortnight in the Italian alps hiking. It’s kind of an adventure to not have access to the net all the time, no ringing of phones, just nature.
Well, nature allows for some fun also.