Difference between 'name' and 'property' argument in ResponseWriter.writeAttribute() - jsf-2

What is the difference between name and property in ResponseWriter.writeAttribute(String name, Object value, String property)? Also, what if property is null?

The name is the HTML attribute name you'd like to write out. The property is the JSF tag attribute name (as indicated by a property on UIComponent class) associated with that HTML attribute.
Usually (and that's for a lot of attributes), those are the same. E.g. <h:inputText value> which ends up as <input value>.
writer.writeAttribute("value", value, "value");
However, for e.g. JSF attribute styleClass this is different, because the associated HTML attribute name class is a reserved keyword in Java and you can't have a property like private String class without facing a compilation error. JSF components therefore use styleClass as tag attribute name and component property. So e.g. <h:inputText styleClass> ends up as <input class>.
writer.writeAttribute("class", styleClass, "styleClass");
The property can be specified with null if there is actually no such attribute in the JSF tag and/or UIComponent class. E.g. custom HTML5 attributes via a custom component or renderer.
writer.writeAttribute("autofocus", "true", null);
So, usually only when both UIComponent#getAttributes() don't contain the key and UIComponent#getValueExpression() returns null and the property is unknown in JSF state.

Related

How to set the styleclass attribute of a JSF component from bean?

I am using Icefaces 3.2. I would like to know how to reset the styleClass attribute of a component e.g textarea from the backing bean method.
USECASE: I have an ace:textAreaEntry which has a validator method in the backing bean. In this backing bean I am doing some validation. If the validation fails I want a particular CSS class applied to the component. So I want to reset the value of the styleclass attribute.
You can set the styleClass conditionally ,like this
<ace:textAreaEntry
styleClass="#{facesContext.validationFailed?'failedClass':'validClass'}"/>
or assign fail class only and otherwise no class at all
<ace:textAreaEntry
styleClass="#{facesContext.validationFailed?'failedClass':''}"/>
If you manually set message to be displayed in your page you can check if facesContext.messageList is empty or not, like this
<ace:textAreaEntry
styleClass="#{(not empty facesContext.messageList)?'filedClass':'validClass'}"/>
If you want to test for some specific internal logic validation you can check for some boolean for example
<ace:textAreaEntry
styleClass="#{(myBean.someComponentFailed)?'filedClass':'validClass'}"/>
where someComponentFailed is some property that you set to true/false upon validation failure

Map being read but not set by HtmlInputText

I have a dynamically created HtmlInputText, which is set to pull its value from a map in a session scoped bean. Like so.
HtmlInputText input = new HtmlInputText();
String expression = "${catalogue.itemValues.A" + item.getId() + "}";
ValueExpression valExpression = expressionFactory.createValueExpression(facesInstance.getELContext(), expression, String.class);
input.setValueExpression("value",valExpression);
where itemValues is a map with a getter of getItemValues() and the key would be A1, A2, etc.
I have programatically added a value to the Map with the key A1 and value 1234. Whenever the JSF page appears, the value is rendered. However, when I change the value and submit the form, the value is not changed.
I have tested with a h:inputText element and linked it to the same key and it is able to update the value and the new value is reflected in the generated HtmlInputText component.
How is this caused and how can I solve it?
You should be using #{} syntax to bind input values, not the ${} syntax. The #{} can do a get and set, while the ${} can only do a get.
See also:
Difference between JSP EL, JSF EL and Unified EL

inputHidden binding to a long id field in backing bean

Just wondering how to set a hidden field value so that when I submit my form, JSF sets it as the id in an object in my CDI-managed bean.
My bean is called "discussionManager" and it has an object in it called 'discussion', which is an entity and therefore has an ID of type Long.
I need the ID so I can look it up and do stuff with it. But, JSF doesn't seem to like numeric hidden fields. It is fine with string fields though. Sure it has something to do with converters or the binding attribute, but can't get the syntax. This is what I'm trying in it's simplest form.
<h:inputHidden id="discussionId" value="#{viewDiscussionBean.discussion.id}"/>
I've tried lots of variations. Can anyone point me in the right direction please?
Thanks
You indeed need to explicitly specify a converter. The JSF builtin LongConverter is suitable.
<h:inputHidden id="discussionId" value="#{viewDiscussionBean.discussion.id}" converter="javax.faces.Long" />

Bean properties not being updated

My bean is viewscoped. I have a simple string property with a getter and setter. The getter works fine(checked by initialising the property), but not the setter. In the setter method I am building a Stringbuffer using each of the incoming parameter.
Code:
public String getParamval() {
return paramval;
}
public void setParamval(String paramval) {
logger.info("Incoming value:" + paramval);
pvals.append(paramval);
this.paramval = "VAL";
}
Is that wrong? I have tested within the setter to see if the input string is being passed but apparently the method is not being called/invoked at all. In the view am using a #{} notation.
View:
<c:forEach items="${gdsiGeodataBean.requiredfields}" var="reqs">
<h:outputLabel value="#{reqs}:* " />
<pou:inputText value="#{gdsiGeodataBean.paramval}" required="true" requiredMessage="Input is required."/>
</c:forEach>
And why would I wanna build a stringbuffer in a setter method? because, the inputtext are created dynamically based on a dynamic list. I only have one bean property to bind to.
I know I could use a map, but for the same reason as above, i seem not able to updated a map values in the setter method. This is connected to the question I asked here Updating a map value in a managed bean
Even though the approach is entirely wrong (the getter won't return the right value after you submit the form!) and I have already answered your previous question as to using the map, the setter should really be called in this particular case.
That the setter is not called can have several causes. The most famous is that the form isn't been placed inside a <h:form> or that you're incorrectly nesting multiple <h:form>s inside each other. Another cause is that the input component or one of its parents have a rendered attribute which happen to evaluate false during the submit request.

How do I break the tyranny of the clientID?

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?
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:
JSF component binding without bean property

Resources