X

@OracleIMC Partner Resources & Training: Discover your Modernization options + Reach new potential through Innovation

Another dynamic form in ADF

I have been recently helping one of Oracle Partners in
migrating their Forms application to the ADF technology. It was a retail store
solution and one of the main requirements was to provide quick and automatic
way to scan and enter the items at the cashier desk. The bar code scanner is a
relatively simple device and can be treated simply as an additional keyboard
attached to the cashier’s computer. To automate entering consequential items at
the desk we need to have a web page with a form which is able to dynamically create
new rows (for new items) detecting some kind of key sequence e.g. enter. This
way the cashier does not have to even touch the keyboard to repetively add new items
to current transaction.

I have created a simple demo application based on the famous
HR schema where the roles of the transaction items play the rows in the REGIONS
table – this is just for sake of simplicity to reproduce it without creating
additional schemas or tables. The form is extremely simple and initially consist
of one inputText field where you can enter some text (here the scanner will
inject the item’s code) and when you press enter the form will create another
field for the next item (with automatic focus) and so on:

You can commit or rollback the new rows/items by using one
of the provided buttons. Of course everything is backed by an ADF View Object
(RegionsView) and powered by all transactional features of ADF. In order to run
the attached sample you need to unpack the application, open it in JDeveloper (v.11.1.1.6),
change the database connection details to point it to your HR schema and run
the provided sql script (create_regions_sequence.sql) to create the additional
sequence for regions ids. Then just launch the reg_form.jspx page.

If you look closer at the application you will see the main
conceptual points which the solution is based on:


1. The underlying view object
is defined in the AM’s data model as “No Rows” to get rid of existing regions
being displayed in the form:



2. Custom java method in the
view object’s java implementation (RegionsViewImpl.java) to insert a new
row at the index of 0:

public void createNewRegionAsFirst() {
Row newRegion = this.createRow();
this.insertRowAtRangeIndex(0, newRegion);
}


3. A method binding in the
reg_form PageDef which calls the abovementioned method at the page first
display (to create first empty row):

4. af:iterator component on
the page bound to the tree model based on RegionsView1 collection. This
iterator is responsible for creating the input components displaying the
region names:

<af:iterator
id="iter" value="#{bindings.RegionsView1.collectionModel}"
var="row"
rows="#{bindings.RegionsView1.rangeSize}"
varStatus="st"
binding="#{backingBeanScope.reg_form_backing.iterator}">
<af:inputText
id="input" value="#{row.bindings.RegionName.inputValue}"
simple="true"
binding="#{backingBeanScope.reg_form_backing.input}">
<af:clientListener
method="onPressEnter" type="keyPress"/>
<af:serverListener
type="newRegionEvent"
method="#{backingBeanScope.reg_form_backing.onNewRegionEvent}"/>
</af:inputText>
</af:iterator>

5. A pair of
af:clientListener and af:serverListener components to handle the enter key
6. Java script method
(reg_form_code.js) to catch and propagate the enter key event to the
server:

function onPressEnter(evt) {
var inputComp = evt.getSource();
var _keyCode = evt.getKeyCode(); //check
for Enter Key
if (_keyCode ==
AdfKeyStroke.ENTER_KEY ){
AdfCustomEvent.queue(inputComp, "newRegionEvent", null, false);
evt.cancel();
}

}

7. A backing bean method
(RegFormBean.java) to handle the enter key on the server site:

public void onNewRegionEvent(ClientEvent clientEvent) {
BindingContainer bindingContainer
= BindingContext.getCurrent().getCurrentBindingsEntry();

OperationBinding createInsert =
bindingContainer.getOperationBinding("createNewRegionAsFirst");

createInsert.execute();

StringBuilder script = new StringBuilder();
//use
client id to ensure component is found if located in
//naming
container
script.append("var textInput = ");
script.append("AdfPage.PAGE.findComponentByAbsoluteId");
script.append ("('"+getFirstClientId()+"');");

script.append("if(textInput != null){");

script.append("textInput.focus();");
script.append("}");

AdfFacesContext.getCurrentInstance().addPartialTarget(iterator);
writeJavaScriptToClient(script.toString());
}

it first calls the
createNewRegionAsFirst binding method to create a row and then generates a
piece of JavaScript code to set the focus on the new row.

To get the dynamically rendered
inputText id it uses the following code:

public String getFirstClientId() {
Object rowKey =
iterator.getRowKey();
String clientId = null;
try
{
iterator.setRowIndex(iterator.getFirst());
clientId =
input.getClientId(FacesContext.getCurrentInstance());
}
finally
{
iterator.setRowKey(rowKey);
}

return clientId;
}

based on the “iterator” and
“input” binding properties bound to the af:iterator and af:inputText
respectively.

8. Finally the same method
for getting the dynamic id of the input text is used to initially set the
focus on the first empty field:

<af:document
id="d1" initialFocusId="#{backingBeanScope.reg_form_backing.firstClientId}">

I hope that the example will prove useful for everyone struggling
with all kinds of ADF dynamic forms. Comments, improvements and suggestions are
as always welcome.

 Best regards,

Lukasz Romaszewski | IMC Migration Center | Oracle


Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha
Oracle

Integrated Cloud Applications & Platform Services