JSF 2.0 buttons click problems

Problem

It is not a discovery, but when you do not know this it can be frustrating.

If you notice that your buttons (h:commandButton or a4j:commandButton) do not response on first click, when you must click two time (double click) to perform an action, this may be a solution for you.

The problem may be caused by form you rendered earlier than click or you rendered element that contains that form.

The case can be like this

<h:form id="rendered"> <!--(1)-->
 <h:commandButton id="button" value="click me twice"/> <!--(2)-->
</h:form>
<h:form> <!--(3)-->
 <a4j:commandButton id="action" action="#{view.action}" render="rendered"/> <!--(4)-->
</h:form>

(1) – FORM THAT LOOSES ITS STATE AFTER “ACTION” BUTTON CLICK
(2) – BUTTON THAT MUST BE CLICKED TWICE TO SEND ACTION REQUEST
(3) – OTHER FORM
(4) – BUTTON THAT WILL RE-RENDER MAIN FORM

or other case

<h:panelGroup id="rendered"> <!--(1)-->
 <h:form><!--(2)-->
  <h:commandButton id="button" value="click me twice"/><!--(3)-->
 </h:form>
</h:panelGroup>
<h:form> <!--(4)-->
 <a4j:commandButton id="action" action="#{view.action}" render="rendered"/><!--(5)-->
</h:form>

(1) – ELEMENT THAT CONTAINS MAIN FORM BUT WILL BE RE-RENDER
(2) – FORM THAT LOOSES ITS STATE AFTER “ACTION” BUTTON CLICK
(3) – BUTTON THAT MUST BE CLICKED TWICE TO SEND ACTION REQUEST
(4) – OTHER FORM
(5) – BUTTON THAT WILL RE-RENDER ELEMENT THAT CONTAINS MAIN FORM

Analyze request

In firebug or other development tool that records requests you can analyze this problem in POST parameters of the request.
After form re-rendering first request on first click will not have javax.faces.ViewState parameter.

rendered rendered
rendered:button click me twice

second request on second click will have this parameter.

javax.faces.ViewState -7190851117743915418:1300621591202567154
rendered rendered
rendered:button click me twice

This is how you can diagnose problem tiwh view state.

Solution

Main cause of this problem is that h:form looses its view state (javax.faces.ViewState). You rendered it first time when page is loaded, and then you re-render this form when you clicked at “action” button, so it is not the same form “rendered” you wanted to react.

Solution is to load all forms (h:form) once per page load. In other words you must render elements elements that is inside form. To solve example problem I just add h:pandelGroup inside form, and named it with form id.

 <h:form>
  <h:panelGroup id="rendered">
   <h:commandButton id="button" value="click me twice"/>
  </h:panelGroup>
 </h:form>
<h:form>
 <a4j:commandButton id="action" action="#{view.action}" render="button"/>
</h:form>

References

http://balusc.blogspot.com/2011/09/communication-in-jsf-20.html#AjaxRenderingOfContentWhichContainsAnotherForm

Advertisements

Managing data in JQuery UI controllers

It’s common this days to use rich UI in web applications. It seems to be natural to use JavaScript based HTML user interface controllers, rather than old fashion re-loadable¬† HTML.

If you are familiar with JS based UI you should remark that many of UI frameworks eg. jQueryUI or Dojo Toolkit has limited number of widgets to use out of the box.

If you need standard UI elements like button, accordion, list, grid/table etc.  you will find it ready to use in frameworks. Unfortunately most of enterprise web applications needs dedicated UI widget.

Usually best way is to use existed widgets and create what is needed.

It is easy to start, implement first events, first functionality, but after 200 lines of JS code it can be painful to maintain simple tasks.

I will show you how I manage states and data in some of my jQuery widgets. This is not best way for official widgets, but it is best for simple widgets created for dedicated applications.

Official, more convenient way using jQueryUI Widget were described on jQueryUI widget page. If you want to create official plugins you should check the official way.

In this article I present only simple way for managing states and data of widget.

Separate HTML elements into jQuery Widgets

Main idea is to not use functions for create widget. It is easy to write.

WRONG WAY


function createList(div, data) {
  for (var d in data) div.append(newRow((d)));
  .. handle list
}
function newRow(text) {
  return jQuery(document.createElement("div")).text(d);
  .. handlers of row
}

You can manage one 1-5 methods like this, but not big widget. Do not write functions for widgets, use jQuery extensions instead.

BETTER WAY

jQuery.fn.myList = function (params) {
  for (var d in params.data) {
    var rowData = {
      data: d,
      list: this
    }
    this.append(jQuery(document.createElement("div")).myRow(rowData));
  }
}
jQuery.fn.myRow = function (params) {
  this.text(params.data.text);
}

Did you notice that I separate list and row for two widget? I did it before in functions for code clean.
But now it is important! Not only to keep code clean but to separate objects that will be created.
Notice that I pass list instance to row. This way I will have reference to container in row.
This is one of condition for element to separate as a widget, if you will need instance of other widget to use.

Params

Ok but what about parameters and default widget definition? In code above I pass object into widget definition, not only data that will be used.

Why I did it this way? To open access to all configuration of widget.I recommend this even when you need only simple data, eg. text for row.
This way you will have open code for changes, eg. to add different style, or different click handler in future.

Also default configuration and configuration extensions will should be always defined at the beginning. Final base of widget will look like this

jQuery.fn.myRow = function (params) {
  var myRowData = jQuery.data(this[0], "myRowData"); // STORED WIDGET DATA
  var def = {};
  if (!myRowData) {
    var def = { // DEFAULT CONFIGURATION
      text: "empty",
      click: function () {}
    }
  } else {
    def = myRowData;
  }
  jQuery.extend(def, params); // EXTEND WIDGET
  this.click(def.click); // EVENT
  jQuery.data(this[0], "myRowData", def); // STORE WIDGET DATA
}

Let’s see what will happen after create myRow widget.

Widget will check if this is first call and widget must be defined or widget must be redefine.

var myRowData = jQuery.data(this[0], "myRowData");
...
if (!myRowData) {
...

For first call default definition is provided, otherwise previous definition is retrieved from data of it’s HTML element.
I prefer to use jQuery.data every time when some data, functions or objects must be connected in some how with HTML elements.
This way I never confused to calling object that I want to call. Object scope is very tricky in JavaSctipt.

After getting new or retrieving old definition of widget, new definition param is used to extend it.

jQuery.extends(def, param);

This way you can pass new functions to handle click or other events or even creation of widget it self if you define those in def object.

At the end definition is linked width HTML element. This part could be stored only at the widget creation, but this way is more readable.

  jQuery.data(this[0], "myRowData", def);

And this is it! Simplest way for widget data manage.
Now you should add creation method and call it when widget is not defined, add events that are defined like below.

this.click(def.click);

Changes for different kind of widget

Remember that, in sample above I pass function to event, so if you would like to change it after widget creation it must be defined in different way.

var _this = this;
this.click(function (ev) {
  var myRowData= jQuery.data(_this[0], "myRowData");
  myRowData.click(ev);
});

Other thing is definition of widget that will be applied for more than one element eg. to all SPANs. Then you must change definition and iterate over all elements in this array rather than use this[0]

Final thought

Always try to separate even simplest part of widget like button, row of list, etc into dedicated widgets.

Happy scripting!