As I may have mentioned previously on this blog, I am currently involved in a somewhat challenging ADF project. We are using JDeveloper 10.1.3.3 and JHeadstart 10.1.3.2 for the development of a hosted web application with over 100 customers with on average two dozen users. One of the real challenges is the implementation of the User Interaction Design: we are not supposed to stick with the Oracle BLAF skin and go for a functional yet slightly boringly robust UI. Instead, the application is to look visually appealing, very Web 2.0 and with close alignment to the actual workflow processes of the business.
The interaction design was made by a Web Designer – who knows HTML, CSS and JavaScript very well – without specific ADF knowledge (or JSF or even Java Web Development for that matter). He did a very good job, creating a consistent, pleasant look & feel with a careful design of the generic workflow. Now it is up to us – the AMIS team – to wrestle with ADF Faces Skins, CSS Stylesheet and a tat of JavaScript here and there. After a couple of weeks, we start to get much of the design implemented in ADF Faces and most of it even generated using JHeadstart – so things are looking good. In a series of articles, I will discuss some of the challenges we faced – and how we overcome them. I will also talk about this at Oracle Open World, on a Thursday afternoon session (Building Real Oracle Application Development Framework (Oracle ADF) Applications: A Learning Experience, S290737, 4-5PM in Moscone South 300).
One of the challenges put to us by the Interaction Design(er) was this one: allow the users to delete records from a multi-record table by clicking on an icon (instead of forcing them to first navigate to a single-record page where a delete button can be clicked or having them check ‘delete checkboxes’ as is custom with JHeadstart applications). Basically, the table layout should look like this:
In this article, I will not discuss the overall look and feel of this page. That is for later installments. We will focus
on the red cross icon and the functionality behind it. Pressing the icon has to bring up a confirmation dialog
and after clicking OK the Employee (BLAKE in this case) will be deleted:
So what is special about this functionality? Well, it turns out not all that much. What we are after is a combination of the SetCurrentRow action with the Delete action. So we need to implement a command link with embedded object image that can trigger two (specific, not anonymously instantiated) actionListeners. Using the <f:actionListener> child element will not do. And the actionListener attribute will take only one actionListener.
So my solution consists of a commandLink with actionListener to set the current row to the employee whose delete icon has been clicked on:
<af:column id="EmpInDeptDeleteColumn" headerText="#{nls['DELETE_COLUMN_HEADER']}" formatType="icon">
<af:commandLink actionListener="#{bindings.setCurrentRowWithKeyEmpInDept.execute}"
onclick="if (confirm('#{nls['GROUP_DELETE_CONFIRM_EMPINDEPT']}')) {return true;}else {return false;}"
action="#{AMISFacesUtil.executeActionBinding}"
shortDesc="Delete Employee">
<af:objectImage source="/menu/images/ic_delete.gif"/>
<af:setActionListener from="#{bindings.DeleteEmpInDept}"
to="#{AMISFacesUtil.actionBindingToExecute}"/>
</af:commandLink>
</af:column>
The commandLink has a setActionListener child element that will set the actionBindingToExecute property on a managed bean AMISFacesUtil to the Delete action binding for the Employee iterator. The action attribute of the commandLink refers to the executeActionBinding method on the AMISFacesUtil bean. This method is almost trivial: it will execute the actionBinding that is currently set on the property actionBindingToExecute:
public String executeActionBinding() {
actionBindingToExecute.execute();
return "";
}
This method returns an empty string to the navigation is to the same page.
The final noteworthy piece of code is the onclick attribute of the commandLink: it is responsible for bringing up the confirmation dialog with a properly i18n text, taken from the Resource Bundle.
Generate this functionality using JHeadstart
Generating this functionality using JHeadstart is fairly straightforward. I have copied the template tableDeleteColumn.vm to AMISTableDeleteColumn.vm. In the template, I removed the selectOneCheckbox that was there and added my own piece of Velocity logic:
<af:commandLink actionListener="#{bindings.setCurrentRowWithKey${JHS.current.group.shortName}.execute}"
onclick="if (confirm('#CONFIRM_DELETE(${JHS.current.group})')) {return true;}else {return false;}"
action="#{AMISFacesUtil.executeActionBinding}">
<af:objectImage source="/menu/images/ic_delete.gif"/>
<af:setActionListener from="#{bindings.Delete${JHS.current.group.shortName}}"
to="#{AMISFacesUtil.actionBindingToExecute}"/>
</af:commandLink>
For the text in the Confirmation dialog, I used a new macro that I added to the common_labels.vm:
#macro (CONFIRM_DELETE $group)
${JHS.nls( "Are you sure you want to delete this ${group.displayTitleSingular}?","GROUP_DELETE_CONFIRM_${group.name}")}#end
It will add a new Resource Bundle entry with key GROUP_DELETE_CONFIRM_nameOfTheGroup and default (English) value: Are you sure you want to delete this Singular name of the Group Entity (here Employee).
To have the JHeadstart Application Generator apply this new template, I have set the TABLE_DELETE_COLUMN template property at the Service Level:
Lucas,
Thank you for your article. I have read it, and it looks promising. I have a question? Where is the Java code that gets the results of the Javascript prompt (true or false)? It’s not clear to me how that true/false result gets passed to the Java bean on the server.
Thanks,
Roland Wales
is there any source for this example, because I don’t understand the “AMISFacesUtil.actionBindingToExecute” means?
plz send me the source code for this example…
Hi,
I wanted to implement a way to delete multiple rows from an ADF Rich Client Table. I have set the rowSelecion property to ‘multiple’. How do I go ahead and implement the multiple row deletions ( I select the records in a details table and click the delete button).
Thanks and regards,
Arun
How do we implement this solution in JDev11g?
Suppose I want to implement it in rich pop up instead of a javascript pop up. how do we do that?
Thanks for your explanation Lucas. I thought it was possible to use the action attribute to directly invoke the delete action instead of first calling a method on a bean, which determines the action binding to be invoked. Using #{bindings.Delete${JHS.current.group.shortName}.execute} on the action attribute of the commandLink. Thinking that on click, the actionListener would be fired first and then the action, deleting the current row. Thanks, Koen
Hi Koen.
The problem is that we need to execute two ActionBindings: first the SetCurrentRowWithKey, then the Delete. As fas as I know, I can only use the actionListener attribute to fire one specific actionListener. The actionListener child elements can only trigger on the fly instantiated action event handlers. So I needed a way to execute this second actionListener. The method I show above seemed the best. However, I am more than open to suggestions for alternatives!
best regards, Lucas
What’s the primary reason you use the AMISFacesUtil to execute the delete? Can’t you just use #{bindings.Delete${JHS.current.group.shortName}.execute} instead? Really looking forward to the upcoming articles. Regards, Koen