a convenient way to set initial focus on input component.
For the inpatient readers: sample workspace to download and start with JDeveloper 11.1.2.1
(11g Release 2) containing a custom tag <adfExt:setInitialFocus/> and a sample usage of it.
<adfExt:setInitialFocus/> features:
- Drag and Drop usage from Control Palette in JDeveloper: ADF Extensions -> Set Initial Focus
- Drop on editable components, like inputText etc.
- Handles multiple usage of the tag - initial focus is placed on first input component rendered in a view
- Handles submit on a same view - the focus should stay where it is
- Handles properties readOnly, disabled, visible of input component.
Initial focus doesn't provide much value in case an input component is not visible or read only. - Works with regions and therefore with components reused multiple times
NOTE: The principles of implementation can be successfully applied in a previous versions (11g R1 with JSF 1.x) , feel free to take a code and adapt it to your needs.
Steps to get the tag into your web project and use it in JDeveloper Component Palette (directory structure of a sample web project is assumed):
- Copy the file SetInitialFocusBehavior.java (implementation of the tag) into your project.
- Copy the file adfExt.taglib.xml (facelets tag library with a definition of it) into WEB-INF\resources directory
- Add the following context parameter into web.xml:
Check if tag library is present in JDeveloper Project Properties:
Once configured, a new library ADF Extensions should be available in JDeveloper Component Palette:
There is one component in a library:
Drag and Drop it on some input component, like af:inputText:
Once the page is rendered, a cursor should be placed on that component:
Lets take a closer look to the use case of "Set Initial Focus" component.
User experience
A user opens an input form (built with ADF Faces) to enter some data. The cursor is placed on first editable field, so he can proceed using a keyboard instead of grabbing a mouse first. After initial focus is set, the user takes a control on cursor position. Once the user took a control and started to navigate ( using TAB or arrow keys), he can finish his work and submit a data entered.
Note: the first input field might not always be the case - a developer might choose the most suitable component to set initial focus on, based on specific requirements.
Developer experience
A software developer might expect to mark a component as a candidate for the initial focus with almost no effort:
- set a property on appropriate component (initialFocus = true)
or - Drag a control, like "Set Initial Focus" from a component palette in JDeveloper and drop it on the input component of a page.
Implementation challenges
ADF is designed for reusability, especially the bounded task flows facilitate that. One of the challenges covered in this blog post from Frank Nimphius is related to the naming containers and the naming path: it is not always a case to know it in advance. It results in difficulties to locate a component in Javascript.
Reusable components are (and shouldn't be) not aware about a usage context of them. The simplest way to set a focus is on the other hand to call a Javascript function focus() on component once it has been rendered. We need to get an instance of component in Javascript, therefore need a client Id in order to find it.
ADF Faces provide a build-in AJAX functionality to reload parts of a page. The implementation using Javascript has to take care about it. In case of partial refresh, a user is still on a same page and doesn't expect the cursor to jump away (see the blog post from Edwin Biemond and the first comment on it).
Addressing the challenges
The implementation of <adfExt:setInitialFocus/> tag is aimed to address the issues described in order to provide an experience users and developers expect. Some new features provided by JSF2 are used.
One of the features used is Behaviour. See the blog post Das Behavior API with a description of it (oups - it is german link, sorry - I took a notice about a language only reviewing a post. I leave the link - modern browsers offer built-in translation, so it helps to google for additional resources in case of interest). My expectation on ClientBehaviour was to get an access to the clientId of component in java code. I'm not sure, if its by design, but one might expect that in case a ClientBehaviour tag is attached, the ADF Faces component renders also a client-peer of it. In that case, there is no need to set a "client Component=true" every time you use initial focus tag. The implementation and my simple tests met the expectation. Drop me a line in case you are familiar with internals of ADF Faces in relation with ClientBehavior.
Facelets in JSF2 allows to build a tag libraries with ease, so it was selected to provide initial focus functionality for developers as custom tag.
The sources of sample project and implementation are available on public Github repository. In case someone might want to extend, rewrite or fix some issue - it is aimed to facilitate that.
It would be nice to get a feedback on usage of the tag - does it behave in your environment like expected?
To finish the post, a snippet of the source provides the rest of implementation details: