1

My least favorite part of coding JSF 2.0 forms has to do with the handing of the id attributes of the various input elements. I am forever having trouble coding the clientID of the target component from within the backing bean, particularly since PrimeFaces tabView now includes the id of the p:tab element as part of the clientID. I waste tons of time coding, testing, then re-coding those clientIDs.

It is reminiscent of older-style assembly language programming where you have to generate tons of label names for your branches and loops. I've done of enough of that for a lifetime.

One approach I am trying is to use only auto-generated id attributes. For example one line of my form might look like this.

<h:outputLabel value="Full Name:" />
<p:inputText value="#{editUser.user.fullName}"
             binding="#{editUser.compFullName}"/>
<p:message for="#{editUser.compFullName.clientId}" />

Note that I do not have an explicit id attribute. Then in the backing bean:

    String clientID = getCompFullName().getClientId();
    msg = new FacesMessage(FacesMessage.SEVERITY_INFO, 
            "Summary Message For Full Name", "Detail Message Full Name");
    FacesContext.getCurrentInstance().addMessage(clientID, msg);

This always works, even if the component has a complex clientID, such as when PrimeFaces inserts the p:tab id into the clientID. (Which it does starting v 3). Rearranging the form never breaks anything.

It is, however, laborious, since I have to create UIComponent properties, getters and setters, and bind them in the form with binding attributes. Can anyone suggest a better way of doing this?

AlanObject
  • 9,613
  • 19
  • 86
  • 142
  • Maybe UIComponent.getCurrentComponent() or getCurrentCompositeComponent() and then use findComponent()/invokeOnComponent() over that component to find the right one? It depends on the context the expression is evaluated, but I suppose it will do the trick (but I'm not 100% sure). – lu4242 Dec 01 '11 at 05:21

1 Answers1

8

since I have to create UIComponent properties, getters and setters, and bind them in the form with binding attributes. Can anyone suggest a better way of doing this?

It's not required to bind the component to some backing bean if you don't use it in there at all. Just bind it to the view instead:

<p:inputText value="#{editUser.user.fullName}"
             binding="#{compFullName}"/>
<p:message for="#{compFullName.clientId}" />

To make the code more self-documenting, I suggest to put a HashMap in the request scope by faces-config.xml:

<managed-bean>
    <description>Holder of all component bindings.</description>
    <managed-bean-name>components</managed-bean-name>
    <managed-bean-class>java.util.HashMap</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
</managed-bean>

with

<p:inputText value="#{editUser.user.fullName}"
             binding="#{components.fullName}"/>
<p:message for="#{components.fullName.clientId}" />

Adding messages is supposed to be done by a Converter or a Validator which is trowing it as a ConverterException or ValidatorException respectively. It will automatically end up in the right message holder. Or if it are informal messages, just add it on the client ID of the UIComponent which is already available as method argument.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 1
    These are really interesting ideas -- I'll play with them a bit. The main reason I was binding to the backing bean is because it is there -- when I have to call the **addMessage** method -- that I have the most trouble. The **id** <-> **for** pairing is not that bad because there you deal with element ids and not clientID. I think what I will try next is to use your managed bean map and inject it into the managed bean that needs the clientID. That way I don't have to create individual **UIComponent** properties and their accessor methods. – AlanObject Dec 01 '11 at 15:49
  • I have the impression that you're actually validating inside a backing bean action method. You should do that in a `Validator` instead. There in you can do `context.addMessage(component.getclientId(), message);` for info messages. Inside an action method, the `addMessage()` is more supposed to be done on `null` client ID only, as kind of a *global* message. – BalusC Dec 01 '11 at 15:51
  • you nailed me. I tend to do edit-checks in the action or actionListener method. I'll re-evaluate. – AlanObject Dec 01 '11 at 20:18
  • @AlanObject: `components` is a request scoped managed bean, so you gonna very limit option on where you can inject. But it is a good idea. Did u play with it and find a way to get it work nicely? – Thang Pham Mar 07 '12 at 21:10