Freitag, 24. Juli 2015

Bulk Delete using Check Box in af:table

Tech stack

Implementation demonstrated in this blog is developed using JDeveloper – version 11.1.1.7.0


Use case

Often times in a project there are requirements to implement a bulk delete functionality. Most of them are expected to be implemented on af:table which will show several rows. There are more than one way this can be achieved. The most common user friendly way is to display check boxes for each row so that the user can simply select the rows that he/she want to delete and finally click on a button to delete them.

In this blog we will look at this approach and how this can be achieved.




Implementation steps

Step 1: We will begin with creating a transient attribute of Boolean type on the VO which is used to show table on the UI.




As you can see we have also changed the “Control Type” attribute in “Control Hints” to Check Box. This will declaratively make this attribute behave like a check box on all layers.


Step 2: On the page fragment where the af:table is present, add the attribute as the first column.



Here, note that we have also set the rowSelection property of af:table to none. This is very important change because we want to programmatically read and handle the VO iterator changes. Also, we have created a table binding which will be used in next step.


Step 3: Create and expose an AM client method which will take a List object as an input. This input parameter will be passed from the UI and will carry all the selected row keys to be deleted.



As shown above, the bulkDeleteEmployees method is created in AMImpl and below exposed as a client method.



This method implements a for-each loop and goes over each element present in the input parameter list. For each element it find the row and removes the same from VO. Finally, a DB commit is performed.


Step 4: Add a button which will be used to delete the selected rows. Partial submit must be enabled on it. Create an action listener method for this button in the managed bean.


The action listener will look like following


The action listener, deleteSelectedEmployees, shown above is doing following:
  1. Taking the handle of the VO iterator which is used to create the table.
  2. Iterating over all the rows present and checking for IsSelected attribute for each row.
  3. If the attribute is returning true it means the row is selected. Adding the key of selected row to a list.
  4. Once all rows are processed, the method is calling the AM method, bulkDeleteEmployees, by passing the list of all selected row keys. The AM method, described in previous step, will take care of deleting the rows and committing changes.
  5. Once done the VO iterator is refreshed and the table binding is triggered to reflect the changes.

Another approach

The same scenario can also be handled without using the check box approach. That will require you to change rowSelection property to multiple on af:table and then programmatically read the selected row keys to delete them. The only drawback with that approach is that it is less recommended UI behaviour and most of the clients go for check box approach for better UI experience.

That’s it! You can download the complete application attached with the blog.
http://www.guardiansoftheoracleworld.com/blogs/adfman/2015/20150723_bulk_delete_using_checkbox_in_table.zip

NOTE: The demo application is based on HR schema. The table I have used is based on the Employees table. If you look at the VO query, I have made a tweak to bring only those employee records who are not managers. If you try to delete a record whose is a manager it will give you foreign key exception and we don’t want to complicate our simple demo by handling that ;)

Happy Coding!

Donnerstag, 25. Juni 2015

Refreshing UI component in Parent TF from nested Child TF

Consider a scenario in which you want to refresh some component present in consuming task flow (parent task flow) upon some action in consumed task flow (child task flow).

To elaborate, you have a task flow and its page fragment (lets say ParentTF.xml and parentPF.jsff). Inside parentPF.jsff there are two components:

  1. An output text component
  2. Another task flow in the form of a region with its own page fragment (lets call it ChildTF.xml and childPF.jsff). There is a command button titled “Refresh” inside childPF.jsff fragment.

Now the requirement is such that when you hit “Refresh” button in child fragment, you want to immediately update the output text value on the parent fragment.

It is a very simple scenario but it can be complicated if there are many levels of child task flows included one inside another. Having multiple parent activity call for all nested task flows is cumbersome. Also, using a complex approach like contextual events for such a simple use case may probably be the last thing in the world you would like to try out.

In this blog we will look at a simple approach of how this can be achieved.

Step 1: Create a bean which will have binding for the output text present on parentPF.jsff and a method to partial trigger the output text. Important thing to note is that this bean is created for this particular special use case and will be registered with ParentTF in request scope. All other UI side logic should be written in separate managed bean.





As you can see there is output text binding added to the bean alongwith a static method refreshParentOutputText().

The beauty here is, anywhere in the application this static method can be called which will refresh the output text, provided the bean is initialized.

Step 2: In the managed bean of ChildTF call the refreshParentOutputText() upon “Refresh” button click. As you can see we are first capturing the input text value in a view scope variable and on “Refresh” button click we are passing the same to refreshParentOutputText() method.




When we run the Index.jspx we will see following:





In above screenshot, the output text component “Refreshed value:” belongs in ParentTF which has ChildTF as a region. Inside ChildTF we have the input text component and Refresh button.
Enter some value in the input text and hit Refresh to see the desired result:




That’s it! You can download the complete application attached with the blog.

Happy Coding!