Friday Nov 25, 2011

How to detect browser type and version from ADF Faces

Sometimes ADF applications need to know about the user browser type and version. For this, assuming you need this information in Java, you can use the Trinidad RequestContext object. You could also use the AdfFacesContext object for the same, but since the ADF Faces Agent class is marked as deprecated, using the equivalent Trinidad classes is the better choice.

The source code below prints the user browser information to the Oracle JDeveloper message window

import org.apache.myfaces.trinidad.context.Agent;
import org.apache.myfaces.trinidad.context.RequestContext;



RequestContext requestCtx = RequestContext.getCurrentInstance();
Agent agent = requestCtx.getAgent();
String version = agent.getAgentVersion();
String browser = agent.getAgentName();
String platform = agent.getPlatformName();
String platformVersion = agent.getPlatformVersion();

System.out.println("==================");
System.out.println("Your browser information: ");
System.out.println("Browser: "+browser);
System.out.println("Browser Version : "+version);
System.out.println("Browser Platform: "+platform);
System.out.println("Browser Platform Version:
"+platformVersion);
System.out.println("==================");


Thursday Nov 24, 2011

Accessing the JSESSIONID from JSF

The following code attempts to access and print the user session ID from ADF Faces, using the session cookie that is automatically set by the server and the Http Session object itself.

FacesContext fctx = FacesContext.getCurrentInstance();
ExternalContext ectx = fctx.getExternalContext();
HttpSession session = (HttpSession) ectx.getSession(false);
String sessionId = session.getId(); 
System.out.println("Session Id = "+ sessionId); 
Cookie[] cookies = 
 ((HttpServletRequest)ectx.getRequest()).getCookies(); 
//reset session string
sessionId = null; 
if
(cookies != null) {
 for (Cookie brezel : cookies) {
     if (brezel.getName().equalsIgnoreCase("JSESSIONID")) {
       sessionId = brezel.getValue();
       break;
     }
  } 
} 
System.out.println("JSESSIONID cookie = "+sessionId);

Though apparently both approaches to the same thing, they are different in the value they return and the condition under which they work. The getId method, for example returns a session value as shown below

grLFTNzJhhnQTqVwxHMGl0WDZPGhZFl2m0JS5SyYVmZqvrfghFxy!-1834097692!1322120041091

Reading the cookie, returns a value like this

grLFTNzJhhnQTqVwxHMGl0WDZPGhZFl2m0JS5SyYVmZqvrfghFxy!-1834097692

Though both seem to be identical, the difference is within "!1322120041091" added to the id when reading it directly from the Http Session object. Dependent on the use case the session Id is looked up for, the difference may not be important.

Another difference however, is of importance. The cookie reading only works if the session Id is added as a cookie to the request, which is configurable for applications in the weblogic-application.xml file. If cookies are disabled, then the server adds the session ID to the request URL (actually it appends it to the end of the URI, so right after the view Id reference). In this case however no cookie is set so that the lookup returns empty. In both cases however, the getId variant works.

Tuesday Nov 22, 2011

Creating ADF Faces Comamnd Button at Runtime

In ADF Faces, the command button is an instance of RichCommandButton and can be created at runtime. While creating the button is not difficult at all, adding behavior to it requires knowing about how to dynamically create and add an action listener reference. The example code below shows two methods: The first method, handleButtonPress is a public method exposed on a managed bean.

public void handleButtonPress(ActionEvent event){ 
 System.out.println("Event handled"); 
 //optional: partially refresh changed components if command 
 //issued as a partial submit
}

The second method is called in response to a user interaction or on page load and dynamically creates and adds a command button. When the button is pressed, the managed bean method – the action handler – defined above is called. The action handler is referenced using EL in the created MethodExpression instance. If the managed bean is in viewScope, backingBeanScope or pageFlowsScope, then you need to add these scopes as a prefix to the EL (as you would when configuring the managed bean reference at design time)

//Create command button and add it as a child to the parent component that is passed as an 
//argument to this method
private void reateCommandButton(UIComponent parent){
  RichCommandButton edit = new RichCommandButton();
  //make the request partial
  edit.setPartialSubmit(true);
  edit.setText("Edit");                         
  
  //compose the method expression to invoke the event handler
  FacesContext fctx = FacesContext.getCurrentInstance();
  Application application = fctx.getApplication();
  ExpressionFactory elFactory = application.getExpressionFactory();
  ELContext elContext = facesCtx.getELContext();
  MethodExpression methodExpressio = null;
  //Make sure the EL expression references a valid managed bean method. Ensure
  //the bean scope is properly addressed 

  methodExpression =  elFactory.createMethodExpression( 
                            elContext,"#{myRequestScopeBean.handleButtonPress}", 
                            Object.class,new Class[] {ActionEvent.class});
  //Create the command buttonaction listener reference

  MethodExpressionActionListener al = null;        
  al= new MethodExpressionActionListener(methodExpression); 
  edit.addActionListener(al); 

   //add new command button to parent component and PPR the component for 
   //the button to show
   parent.getChildren().add(edit);
   AdfFacesContext adfFacesContext = AdfFacesContext.getCurrentInstance(); 
   adfFacesContext.addPartialTarget(parent); 
}

How-to read data from selected tree node

By default, the SelectionListener property of an ADF bound tree points to the makeCurrent method of the FacesCtrlHierBinding class in ADF to synchronize the current row in the ADF binding layer with the selected tree node. To customize the selection behavior, or just to read the selected node value in Java, you override the default configuration with an EL string pointing to a managed bean method property. In the following I show how you change the selection listener while preserving the default ADF selection behavior.

To change the SelectionListener, select the tree component in the Structure Window and open the Oracle JDeveloper Property Inspector. From the context menu, select the Edit option to create a new listener method in a new or an existing managed bean.

For this example, I created a new managed bean. On tree node select, the managed bean code prints the selected tree node value(s)


import java.util.List;

import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.MethodExpression;
import javax.faces.application.Application;
import javax.faces.context.FacesContext;

import java.util.Iterator;  
import oracle.adf.view.rich.component.rich.data.RichTree;
import oracle.jbo.Row;
import oracle.jbo.uicli.binding.JUCtrlHierBinding;
import oracle.jbo.uicli.binding.JUCtrlHierNodeBinding;
import org.apache.myfaces.trinidad.event.SelectionEvent;

import org.apache.myfaces.trinidad.model.CollectionModel;
import org.apache.myfaces.trinidad.model.RowKeySet;
import org.apache.myfaces.trinidad.model.TreeModel;  
public class TreeSampleBean {
 public TreeSampleBean() {}
 public void onTreeSelect(SelectionEvent selectionEvent) {
  //original selection listener set by ADF
  //#{bindings.allDepartments.treeModel.makeCurrent}
  String adfSelectionListener = "#{bindings.allDepartments.treeModel.makeCurrent}";
  //make sure the default selection listener functionality is 
  //preserved. you don't need to do this for multi select trees 
  //as the ADF binding only supports single current row selection  
 
  /* START PRESERVER DEFAULT ADF SELECT BEHAVIOR */
  FacesContext fctx = FacesContext.getCurrentInstance();
  Application application = fctx.getApplication();
  ELContext elCtx = fctx.getELContext();
  ExpressionFactory exprFactory = application.getExpressionFactory();
  
  MethodExpression me = null;
  me = exprFactory.createMethodExpression(elCtx, adfSelectionListener, 
                                          Object.class, newClass[]{SelectionEvent.class}); 
  me.invoke(elCtx, new Object[] { selectionEvent });  

  /* END PRESERVER DEFAULT ADF SELECT BEHAVIOR */
  RichTree tree = (RichTree)selectionEvent.getSource();
  TreeModel model = (TreeModel)tree.getValue();   
 
  //get selected nodes
  RowKeySet rowKeySet = selectionEvent.getAddedSet(); 
  Iterator rksIterator = rowKeySet.iterator(); 
  //for single select configurations,this only is called once 
  while (rksIterator.hasNext()) {
    List key = (List)rksIterator.next();
    JUCtrlHierBinding treeBinding = null;
    CollectionModel collectionModel = (CollectionModel)tree.getValue();
    treeBinding = (JUCtrlHierBinding)collectionModel.getWrappedData(); 
    JUCtrlHierNodeBinding nodeBinding = null;
    nodeBinding = treeBinding.findNodeByKeyPath(key);
    Row rw = nodeBinding.getRow();
    //print first row attribute. Note that in a tree you have to 
    //determine the node type if you want to select node attributes 
    //by name and not index 
    String rowType = rw.getStructureDef().getDefName();
  
    if(rowType.equalsIgnoreCase("DepartmentsView")){
      System.out.println("This row is a department: " +  
                         rw.getAttribute("DepartmentId"));
    }
    else if(rowType.equalsIgnoreCase("EmployeesView")){
     System.out.println("This row is an employee: " + 
                         rw.getAttribute("EmployeeId"));
    }     
    else{
      System.out.println("Huh????");  
    }
    // ... do more useful stuff here   
  }   

}

--------------------

Download JDeveloper 11.1.2.1 Sample Workspace


Thursday Nov 17, 2011

Reading train stop display names from a resource bundle

In Oracle JDeveloper 11g R1, you set the display name of a train stop of an ADF bounded task flow train model by using the Oracle JDeveloper Structure Window.

To do so

  • Double-click onto the bounded task flow configuration file (XML) located in the Application Navigator so the task flow diagram open
  • In the task flow diagram, select the view activity node for which you want to define the display name.
  • In the Structure Window., expand the view activity node and then the train-stop node therein
  • Add the display name element by using the right-click context menu on the train-stop node, selecting Insert inside train-stop > Display Name
  • Edit the Display Name value with the Property Inspector

Following the steps outlined above, you can define static display names – like "PF1" for page fragment 1 shown in the image below - for train stops to show at runtime.

In the following, I explain how you can change the static display string to a dynamic string that reads the display label from a resource bundle so train stop labels can be internationalized.

There are different strategies available for managing message bundles within an Oracle JDeveloper project. In this blog entry, I decided to build and configure the default properties file as indicated by the projects properties. To learn about the suggested file name and location, open the JDeveloper project properties (use a right mouse click on the project node in the Application Navigator and choose Project Properties.

Select the Resource Bundle node to see the suggested name and location for the default message bundle. Note that this is the resource bundle that Oracle JDeveloper would automatically create when you assign a text resource to an ADF Faces component in a page.

For the train stop display name, we need to create the message bundle manually as there is no context menu help available in Oracle JDeveloper. For this, use a right mouse click on the JDeveloper project and choose New | General | File from the menu and in the opened dialog.

Specify the message bundle file name as the name looked up before in the project properties Resource Bundle option. Also, ensure that the file is saved in a directory structure that matches the package structure shown in the Resource Bundle dialog. For example, you would save the properties file in the View Project's src > adf > sample directory if the package structure was "adf.sample" (adf.sample.ViewControllerBundle).

Edit the properties file and define key – values pairs for the train stop component. In the sample, such key value pairs are

TrainStop1=Train Stop 1
TrainStop2=Train Stop 2
TrainStop3=Train Stop 3

Next, double click the faces-config.xml file and switch the opened editor to the Overview tab. Select the Application category and press the green plus icon next to the Resource Bundle section.

Define the resource bundle Base Name as the package and properties file name, for example

adf.sample.ViewControllerBundle

Finally, define a variable name for the message bundle so the bundle can be accessed from Expression Language. For this blog example, the name is chosen as "messageBundle".

<resource-bundle>
  <base-name>adf.sample.ViewControllerBundle</base-name>
  <var>messageBundle</var>
</resource-bundle> 

Next, select the display-name element in the train stop node (similar to when creating the display name) and use the Property Inspector to change the static display string to an EL expression referencing the message bundle. For example:

#{messageBundle.TrainStop1}

At runtime, the train stops now show display names read from a message bundle (the properties file).

Friday Oct 14, 2011

How to programmatically set focus on an input component

The af:document component has a property InitialFocusId that allows you to define the Id of an input component that should take focus when a page initially loads. But how do you set the component focus for pages that are already rendered? A use case for this is a partial submit that executes logic on the server, after which the cursor focus in the UI needs to be set to a specific input component of a page or page fragment. The solution to this use case is JavaScript that is generated on the server and executed on the client.

The simplified sample I wrote contains of three input text fields and three command buttons. Initially, using the af:document InitialFocusId property, the cursor focus is set to the first input text field.

The command button send a partial submit to a managed bean on the server. The managed bean reads the component Id of the input text field to put the focus to from a client attribute that is defined on each command button. Using the MyFaces Trinidad ExtendedRenderKitService class, the managed bean sends a JavaScript call to the client to change the current component focus.

Important: By default, ADF Faces does not render all its user interface components as JavaScript objects. It only renders those components as JavaScript objects that have behavior, like a table that can have its columns moved. Input text components, for example, are rendered in HTML only, which means that the ADF client side JavaScript framework will not find a handle to the component unless you tell ADF Faces to create one. For this, you set the ClientComponent property of the input text fields to true. This also is required for the af:document InitialFocusId property to work.

Below is the managed bean code that handles the command button action and that composes and executes the JavaScript to set the client side UI focus.

import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import oracle.adf.view.rich.component.rich.input.RichInputText;
import oracle.adf.view.rich.component.rich.nav.RichCommandButton;
import org.apache.myfaces.trinidad.render.ExtendedRenderKitService;
import org.apache.myfaces.trinidad.util.Service;
public
class FocusBean {
  public FocusBean() {
  }

 public String onSetFocus(ActionEvent event) {
   RichCommandButton rcb = (RichCommandButton)event.getSource();
   String focusOn = (String)rcb.getAttributes().get("focusField");
   FacesContext fctx = FacesContext.getCurrentInstance();
   UIViewRoot viewRoot = fctx.getViewRoot();
  //search can be improved to include naming containers
  RichInputText rit = RichInputText)viewRoot.findComponent(focusOn);
 if (rit != null) {
   String clientId = rit.getClientId(fctx); 
   //compose JavaScript to be executed on the client 
   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 ("('"+clientId+"');");
 
   script.append("if(textInput != null){"); 
   script.append("textInput.focus();");
   script.append("}");
   //invoke JavaScript
   writeJavaScriptToClient(script.toString());
  }  
 }
  //generic, reusable helper method to call JavaScript on a client
  private void writeJavaScriptToClient(String script) {
    FacesContext fctx = FacesContext.getCurrentInstance();
    ExtendedRenderKitService erks = null;
    erks = Service.getRenderKitService(
                 fctx, ExtendedRenderKitService.class);
    erks.addScript(fctx, script);
  }
}

 As mentioned, the command buttons in the sample have a client attribute attached that I use to determine which input component should receive focus. The managed bean calls the client attribute here:

RichCommandButton rcb = (RichCommandButton)event.getSource();
String focusOn = (String)rcb.getAttributes().get("focusField");

 In the page definition, the client attribute is defined as

<af:commandButton text="Focus Field 2" id="commandButton1"
                   partialSubmit="true"
                   actionListener="#{FocusBean.onSetFocus}">
  <af:clientAttribute name="focusField" value="it2"/>
</af:commandButton>
<af:commandButton text="Focus Field 3" id="cb1"
                  partialSubmit="true"
 actionListener="#{FocusBean.onSetFocus}">
  <af:clientAttribute name="focusField" value="it3"/>
</af:commandButton>

In your custom implementation of this use case, you for sure will have your own way of determining the next focus target. The server side code however doesn't change much.

You can DOWNLOAD the sample workspace from here: http://blogs.oracle.com/jdevotnharvest/resource/SetFocusToField.zip


Friday Jul 08, 2011

How-to access UI component that queued a custom client event

In ADF Faces, to invoke a server side method in a managed bean, you use the af:serverListener tag. The af:serverListener tag is added as a child to the component that owns the event and called from JavaScript in a call to AdfCustomEvent.queue( … )

In this example, the af:serverListener is added to a table to notify a manage bean method about a double-click action.

<af:table ...>
 <af:column> ... </af:column>
 ...
 <af:clientListener method="handleTableDoubleClick"
                   type="dblClick"/>
<af:serverListener type="TableDoubleClickEvent"                          
                   method="#{myBean.handleTableDoubleClick}"/>
</af:table> 

The JavaScript function that is called by the af:clientListener is shown next.

function handleTableDoubleClick(evt){   
  var table = evt.getSource();
  AdfCustomEvent.queue(table, "TableDoubleClickEvent",{}, true);         
  evt.cancel();
}

The first argument in the call to AdfCustomEvent.queue represents the event owner, the table component. This information is passed to the managed bean method, which has the following signature.

public void handleTableDoubleClick(ClientEvent ce){
  RichTable richTable = (RichTable)ce.getComponent(); 
  //... work with rich table component
}

As you can see, there is no need to look up the event owning component by searching the JSF UIViewRoot with or without help of JSFUtils.

Thursday Jul 07, 2011

New client behavior tag - af:checkUncommittedDataBehavior

In Oracle JDeveloper 11.1.2, a new client behavior tag af:checkUncommittedDataBehavior is provided to check for uncommitted data when navigating away from a page using a command button that has its immediate property set to true. The tag can be applied as a child of any command component, like

  • af:commandButton
  • af:commandLink
  • af:commandMenuItem
  • af:commandToolbarButton

http://download.oracle.com/docs/cd/E16162_01/apirefs.1112/e17491/tagdoc/af_checkUncommittedDataBehavior.html

For the client behavior to work, you must set the document tag's uncommittedDataWarning attribute to on.

Just as a reminder: Client behavior tags in ADF Faces execute on the client side. They are there to save you from writing JavaScript, thus abstracting you from the complexity of the underlying client side APIs.

Wednesday Jun 08, 2011

If the stand alone Oracle Skin Editor does not start on Windows

One of the new features in Oracle JDeveloper 11.1.2 is the ADF Faces Skin Editor for building pluggable application look and feels declaratively. However, the ADF Faces Skin Editor is also available in a stand-alone version for developers building skins for existing applications built with previous versions of Oracle JDeveloper 11g and for web designers that are tasked with building a look and feel but don't need the full Oracle JDeveloper 11g installed.

http://www.oracle.com/technetwork/developer-tools/adf/downloads/index.html

The ADF Faces Skin Editor comes in a ZIP file that you extract on your local machine. The parent folder the software unzips itself into is called skineditor and developers most likely feel attempted to change the folder name to include additional information like the version number (11.1.2.0.0) or the vendor (Oracle). However, an issue with the skin editor is that it requires the parent folder name to be skineditor. It only allows the writing to be in mixed case, but no change to the name itself.

When changing the parent folder name, for example skineditor_11_1_2_00, then, when starting the skin editor, the Splash Screen is shown but the editor itself does not come up, though the process entry for the skineditor64W.exe is visible in the Windows Task Manager.

Note that the reason for this behavior is that skineditor, which becomes the root folder of the software after unzipping it, is not considered to be the installation folder. The skineditor folder is considered to be part of the software and thus cannot be changed. To create a meaningful name for the folder hosting the skin editor software, unzip the software into an installation folder you create before. This can then have version numbers in it but must not have blanks in the naming.

Wednesday May 25, 2011

Invoking af:exportCollectionActionListener from Java

The af:exportCollectionListener tag is a client behavior tag in ADF Faces. Client behavior tags implement functionality that requires JavaScript on the client side if coded manually by application developer. In fact, client behavior tags wrap the JavaScript that is required for a solution and expose a JSF tag for declarative use instead. The af:exportCollectionListener exports the visible content of a collection, like exposed in an ADF Faces table, to Excel. The tag is dragged on top of a command item, like a toolbar button or a command button, and then configured with the table id for which rows should be exported, the name of the file to produce, whether you want to export all rows or just those that are selected, and an optional title string. For more information, see the tag documentation:

http://download.oracle.com/docs/cd/E17904_01/apirefs.1111/e12419/tagdoc/af_exportCollectionActionListener.html

When the command item that has the af:exportCollectionListener tag added is invoked by a user, the tag is executed as well and produces the desired output. However, applications usually are a lot more dynamic than to wait for a user to press a button. Instead developers may want to invoke the client behavior programmatically, which in case of a client behavior you can do using JavaScript

var button = AdfPage.PAGE.findComponentByAbsoluteId('pc1:ctb1');
if (button != null)
{
  AdfActionEvent.queue(button);
}  

The JavaScript code above looks an ADF Faces component up in a search from the page root. The component is identified by its absolute component Id ('pc1:ctb1' in the example as the button is in a toolbar facet of a panel collection, which is a naming container). If the component is found, the client event – AdfActionEvent – is queued for the button, which virtually presses it.

However, what if you don't want JavaScript in your application code? In this case, you can use Java to invoke JavaScript from a managed bean. The following code sample provides a method that is called from Java logic in your managed bean to composes the JavaScript String and to invoke it on the client:

import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import org.apache.myfaces.trinidad.render.ExtendedRenderKitService;
import org.apache.myfaces.trinidad.util.Service;  
public void magicallyPressToolbarCommand(String id) {
  FacesContext fctx = FacesContext.getCurrentInstance();
  UIViewRoot uiViewRoot = fctx.getViewRoot();
  UIComponent comp = uiViewRoot.findComponent(id);
  //check if the component is a command component. For the 
  //exportCollectionListener this is important as we need to 
  //queue a client side action event
  if (comp != null && (comp instanceof UIXCommand)) {
    String clientId = comp.getClientId(fctx);
    StringBuffer scriptBuffer = new StringBuffer();
    scriptBuffer.append("var button = 
                       AdfPage.PAGE.findComponentByAbsoluteId('");
    scriptBuffer.append(clientId + "');");
    scriptBuffer.append("if (button != null){");
    scriptBuffer.append("AdfActionEvent.queue(button);}");
    writeJavaScriptToClient(scriptBuffer.toString());
  } 
  else {
    //ID probably not found. Log the issue
     System.out.println("Component with ID " + id + " not Found !!!");
    //TODO - use proper ADFLogger print message
  }
}
//universal helper method for invoking scripts on the client
private void writeJavaScriptToClient(String script) {
  FacesContext fctx = FacesContext.getCurrentInstance();
  //Trinidad classes
  ExtendedRenderKitService erks = null;
  erks = Service.getRenderKitService(fctx,
  ExtendedRenderKitService.class);
  erks.addScript(fctx, script);

}

What you need to pay extra attention to is the ID of the component ( a toolbar component in my example). If a component is within a naming container like PageTemplate, Table, PanelCollection, Region, etc. then the ID(s) of the surrounding naming containers must be added as a prefix to the component ID. The form is namingContainerId:componentId.

Disadvantage of using JavaScript in Java: The script is harder to debug on the client.

One more challenge!

Okay, now that I showed how to invoke a command item on a client using JavaScript from Java, what if you don't want to have a button showing in the UI? In this case, it should be the application logic only that invokes the af:exportCollectionAtionListener. In this case you still add a command item to the page but set its Visible property to false. This way the command item is hidden in the user interface, but the functionality is still available for the application to use.

Note: Don't however try the same setting the "Rendered" property to false. If a component is not rendered then it cannot be found and invoked on the client.

Tuesday Nov 30, 2010

Get social security numbers right

A common development use case is to guide users when working with input fields that require a specific input format. For example, credit card and social security number fields use character delimiters that you may want to enforce on a field. The following sample uses JavaScript to add a defined delimiter character according to a defined character.

The American social security pattern is defined as xxx-xx-xxxx. Users that type 123456789 should have the input automatically corrected to 123-45-6789 while they type. Also, the field should be protected from character input and input length larger than the provided pattern.

<af:inputText label="Social Security Number" id="it1"
rendered="true">
<af:clientListener
method="handleNumberFormatConversion('xxx-xx-xxxx','-')"
type="keyDown"/>
</af:inputText>

With the above configuration, the handleNumberFormatConversion method is called for each key stroke in the input field. Additional arguments provided to the function are the input pattern and the character delimiter.

The JavaScript code that is addressed by the clientListener on the InputText is shown below:

// JavaScript function that applies a specific format
// to numeric input. The pattern argument defines the
// input mask, e.g. xxx-xx-xxxx. The delimiter defines
// the delimiter character to add to the user input based
// on the pattern

function handleNumberFormatConversion(pattern, delimiter){
return function(evt){
var inputField = evt.getCurrentTarget();
var keyPressed = evt.getKeyCode();
var oldValue = inputField.getSubmittedValue();
//keycode 48-57 are keys 0-9
//keycode 96-105 are numbpad keys 0-9

var validKeys = new Array(48,49,50,51,52,53,54,55,
56,57,96,97,98,99,100,
                                 101,102,103,104,105,
AdfKeyStroke.ARROWRIGHT_KEY,
AdfKeyStroke.ARROWLEFT_KEY,
AdfKeyStroke.BACKSPACE_KEY,
AdfKeyStroke.DELETE_KEY,
AdfKeyStroke.END_KEY,
AdfKeyStroke.ESC_KEY,
AdfKeyStroke.TAB_KEY);

var numberKeys = new Array(48,49,50,51,52,53,54,55,
56,57,96,97,98,99,100,
101,102,103,104,105);

var isValidKey = false;
for (var i=0; i < validKeys.length; ++i){
if (validKeys[i] == keyPressed) {
isValidKey = true;
break;
}
}
if(isValidKey){
//key is valid, ensure formatting is correct
var isNumberKey = false;
for (var n=0; n < numberKeys.length; ++n){
if(numberKeys[n] == keyPressed){
isNumberKey = true;
break;
}
}
if(isNumberKey){
//if the user provided enough data, cancel
//the input
var formatLength = pattern.length;
if(formatLength == oldValue.length){
inputField.setValue(oldValue);
evt.cancel();
}
//more values allowed. Check if delimiter needs to
           //be set
else{
//if the date format has a delimiter as the next
//character, add it
if(pattern.charAt(oldValue.length)== delimiter){
oldValue = oldValue+delimiter;
inputField.setValue(oldValue);
}
}
}
}
else{
//key is not valid, so undo entry
inputField.setValue(oldValue);
evt.cancel();
}
}
}

The sample is for number only input. However, changing it for character or mixed input is not difficult to do. Note however that you can't use this with af:inputDate component because this component doesn't work well when setting String formatted values as the value property. (At least my debugging showed this)

About

The Oracle JDeveloper forum ranks in the Top 5 of the most active forums on the Oracle Technology Network (OTN).



The OTN Harvest blog is a summary of selected topics posted on the OTN Oracle JDeveloper forum.



It is an effort to turn knowledge exchange into an interesting read for developers who enjoy little nuggets of wisdom





Frank Nimphius

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today