Monday, 8 June 2015

Focus HTML element after AJAX call with PrimeFaces


Introduction

The combination of AJAX updates to the screen and the focus of a field is more then once an issue for the developer. And this is not an issue of PrimeFaces, but comes with the fact of using AJAX.

This blog explains what you can due in the 2 most important scenarios what you normally encounter.

Problem description

Image you have on the screen 2 input fields, field A en field B.  There is an onBlur handler attached to field A which does a partial update of the screen, containing field B, with an AJAX call.

So what happens when the user is in field A en tabs out of the field? Leaving the field, results in the trigger of the onBlur handler. During the time that the AJAX calls is performed asynchronously, the browser performs the standard behaviour, and thus the focus is placed in the field B.

But then the AJAX call returns and results in updating the screen, and there are use cases where the developer decided to replace the field B. And since it is a replacement of the element in the DOM tree, the focus which was original in the field B is now lost because the field is replaced by another element.

Fixing focus issue

The first scenario describes the situation where the focus must be placed in a certain field which is updated by the AJAX call.  But it is always the same field regardless of the result of the server side code.

This can easily achieved by using the oncomplete attribute of the PrimeFaces widget who initiated the AJAX call.
This is JavaScript code which is performed when the AJAX call was successful (and thus there was no error) and the replacement of the DOM elements in the browser is completed.
So at this point the DOM tree is stable again and we can give a field the focus.

oncomplete="PrimeFaces.focus('frm:newProjectName');"

The above snippet places the focus in the newProjectName field when the AJAX is finished.

Conditionally define the focus

Another scenario is where the fields that needs to get the focus needs to be defined conditionally.  Lets examen this use case better with some screen example.



In the above case, we have a field to enter some kind of code.  And depending on the code, we sometimes needs additional information from the user.
So, there will be an AJAX handler (p:ajax) which call some java listener method to perform the server side functionality which defines if there is additional information needed. 

Initially the 'additional' field is disabled, so the focus is not placed in this field by the browser. And since the field is replaced by the AJAX call in the DOM tree, the focus would be lost anyway.

But from within the Java listener method, we can execute some JavaScript when the AJAX call is finished.  This is one of the great features of PrimeFaces.

So, by adding the following code in the Java method, we can place the focus in the additional field. And within Java it is easy when this focus must be placed there (the conditional aspect of this usecase)

RequestContext.getCurrentInstance().execute("PrimeFaces.focus('frm:additionalInfo');");

Conclusion

The focus and AJAX combination has some conflicts. In the Expert group for JSF 2.3, they are considering some additional tags to handle those situations.
Within PrimeFaces, we saw with 2 usecases that you can manage the problem with the usage of the excellent integration of JavaScript within PrimeFaces. This from within the view (JSF pages) as from within Java.

Have fun.