Conditionally render JSF h:panelGrid based on presence of query string (or no query string at all) - jsf

I'm trying to dynamically render some composition/templates based on the presence of a query string or the absence of a query string. For example:
localhost:9080/myWonderfulApp/test.xhtml?foo=bar
This works, A.xhtml gets pulled in.
localhost:9080/myWonderfulApp/test.xhtml
This doesn't work, B.xhtml does not get pulled in.
I'm having problems with the absence of a query string part. I can render A.xhtml when I pass ?foo=bar, but I can't seem to get B.xhtml rendered when I have no query string. I've tried some variations, I initially figured #{param['foo'] != 'bar' would work, but I think that's not working because I don't have a foo query param at all. I've tried checking if param == null but that didn't work either.
Is it possible to set my rendered attribute based on NO query string?
I can't just set another query string for B.xhtml, either as I'm working on a legacy app that gets 2 different skins, so retrofitting all the old apps that link in isn't an option. New apps will use a query string, old ones need to get an old skin linking in with no query string.
<!--This works-->
<h:panelGrid rendered="#{param['foo'] == 'bar' ? true : false}">
<ui:composition template="A.xhtml">...</ui:composition>
</h:panelGrid>
<!--This doesn't work-->
<h:panelGrid rendered="#{param == null ? true : false}">
<ui:composition template="B.xhtml">...</ui:composition>
</h:panelGrid>
This doesn't seem to work, either:
<h:panelGrid rendered="#{empty facesContext.externalContext.requestParameterMap.foo ? true : false}">

You just need the inverse condition: #{param.foo != 'bar'}. Those conditional operators returning booleans are unnecessary, the equation itself returns a boolean already. The #{param} is never null. It returns a Map<String, String> which is just empty (not null!) when it doesn't contain any parameters. The brace notation is only useful when the parameter name contains periods which would otherwise be interpreted as nested properties, but request parameter names shouldn't contain periods anyway.
So, this should do:
<h:panelGrid rendered="#{param.foo == 'bar'}">
<ui:composition template="A.xhtml">...</ui:composition>
</h:panelGrid>
<h:panelGrid rendered="#{param.foo != 'bar'}">
<ui:composition template="B.xhtml">...</ui:composition>
</h:panelGrid>
As a different alternative, if you want to use the conditional operators the right way, you can also do
<ui:composition template="#{param.foo == 'bar' ? 'A' : 'B'}.xhtml">...</ui:composition>

Related

javax.el.PropertyNotWritableException when using EL conditional operator in value of UIInput

I get this error message:
javax.el.PropertyNotWritableException: /u/editProfile.xhtml #64,140 value="#{empty userProfile.cfg.gpu or userProfile.cfg.gpu == '' ? usernavmsg.EditMe: userProfile.cfg.gpu}": null
The problem is that when the value of a bean property is null the value of an inputText field switches from my ManagedBean property, to a resource string. So I cannot persist that value.
I request the profile of the user from my database in my managed bean. If a property of the said profile is null, the inplace text holder value is "Edit Me". If it's not null it's the value of that property. Which is working ! However when I submit the form and try to persist a new value or no value at all the error appears. The error only appears for the field that are null to begin with (when I requested them from the db). So the problem is that when the value is null it switch from my ManagedBean property, to a resource string.
I just have a form with this:
<h:outputLabel value="#{usernavmsg.GPU}: "/>
<p:inplace styleClass="lessDark">
<p:inputText value="#{empty userProfile.cfg.gpu ? usernavmsg.EditMe: userProfile.cfg.gpu}" />
</p:inplace>
when I submit the form I want to persist userProfile.cfg in the database which doesn't happen.
Can I work around this ? Is it even possible ?
Conditional statements in EL are indeed not writable. They are read-only. End of story. The same applies to method references in EL as in #{bean.property()}. It must really be a true value expression as in #{bean.property}.
Your approach of using a (HTML5) "placeholder" is actually wrong. For that you should be using the placeholder attribute, not the value attribute. In older versions of PrimeFaces that do not have a placeholder attribute you'll need passthrough.
<html ... xmlns:a="http://xmlns.jcp.org/jsf/passthrough">
...
<p:inputText value="#{userProfile.cfg.gpu}" a:placeholder="#{usernavmsg.EditMe}" ... />
Nowadays PrimeFaces offers a placeholder attribute.
<p:inputText value="#{userProfile.cfg.gpu}" placeholder="#{usernavmsg.EditMe}" ... />

How can I add attributes to components which don't have their own renderers using the f:attribute component?

I want to write a custom renderer for the h:selectOneMenu component and eventually make use of the description property of the UISelectItem class to add a title a.k.a. tooltip to f:selectItems following BalusC's profound guides in https://stackoverflow.com/a/25512124/3280015 and http://balusc.blogspot.de/2008/08/styling-options-in-hselectonemenu.html.
Now I did extend the com.sun.faces.renderkit.html_basic.MenuRenderer in my own CustomMenuRenderer, registered it with the faces-config.xml and overrode the renderOption method, adding the following code before option tag is terminated by the Responsewriter:
String titleAttributeValue = (String) component.getAttributes().get("title");
if (titleAttributeValue != null) {
String indexKey = component.getClientId(context)
+ "_currentOptionIndex";
Integer index = (Integer) component.getAttributes().get(indexKey);
if (index == null) {
index = 0;
}
component.getAttributes().put(indexKey, ++index);
}
I'm not quite sure I'm doing the indexKey thing right or whether I need it for the title attribute or should use a writer.writeAttribute("title", titleAttributeValue, null); instead because I don't have a list like in the optionClasses tutorial, but the code works so far!
In the actual view definition use case I did:
<h:selectOneMenu value="#{cc.data}">
<f:attribute name="title" value="outerTEST" />
<c:forEach items="#{cc.list}" var="val">
<f:selectItem value="#{val}" itemValue="#{val}" itemLabel="#{val.label}">
<f:attribute name="title" value="innerTEST #{val.description}" />
</f:selectItem>
</c:forEach>
</h:selectOneMenu>
(I just put the #{val.description} there in the title value to clarify my intention, it is currently still empty and I will have to think about how to populate it per element later, but for the sake of the question we can assume it is already filled.)
But now I'm getting the "outerTEST" properly showing up in the title attribute of the option in the resulting XHTML in the Browser, yet I'm not seeing any of the "innerTEST" which would and should be individual per selectItem and which is what this is eventually all about.
I understand the f:selectItem and f:selectItemscomponents do not have their own renderers but rendering of options is generally handled by the MenuRenderer via its renderOption method.
But how then would I add individual titles to the individual selectItems??
Thanks

Evaluation with <c:when> in data table doesn't work

I have searched and tried but this time I'm really stuck.
I am trying to build a simple datatable (primefaces) where the cell content can be of different types. There is a holder class for each cell content that can hold different entities and I want to use < c:choose> to check and display the right entity in the entity specific way.
The code looks like:
<p:dataTable emptyMessage="" value="#{date.getThreadContent(column.propertyID)}" var="content">
<p:column>
#{content.type}
<c:choose>
<c:when test="#{content.type == 'activity'}">
#{content.activity.name}
</c:when>
<c:when test="#{content.type == 'todo'}">
#{content.activity.name}
</c:when>
<c:otherwise>
Neither activity or todo
</c:otherwise>
</c:choose>
</p:column>
</p:dataTable>
The EL evaluation doesn't work regardless if I try a boolean or String values in the bean (I'm using String value in the code above).
So each time the content is not empty, the output first displays the correct content type from #{content.type} but then together with 'Neither activity or todo'.
I can also say that this data table itself represents a cell content in a parent data table (list of entities per date) that is not visible in this code as I try to isolate the problem.
Could it be that this type of expression cannot be done in a ?
Any help is appreciated.
Use JSF rendered tags to do your conditional display logic, it removes it from the DOM completely and makes validations easier.
Refer: http://docs.oracle.com/javaee/6/tutorial/doc/bnaik.html for EL expressions
Also a good explanation is provided by BalusC here: JSTL c:if doesn't work inside a JSF h:dataTable
<p:dataTable emptyMessage="" value="#{date.getThreadContent(column.propertyID)}" var="content">
<p:column>
#{content.type}
<h:outputText value="#{content.activity.name}" rendered="#{content.type == 'activity' or content.type == 'todo'}" />
<h:outputText value="Neither activity or todo" rendered="#{content.type != 'activity' and content.type != 'todo'}" />
</p:column>
</p:dataTable>

JSF Hide Negative Mark when using f:convertNumber

I want to hide the minus value from the print during formatting in JSF. How can I achieve that.
For Example,
The Value : -340
Need to Display as : 340.00
Not like -340.00 or (340.00)
Is that possible? The current code is like that, but can not hide minus value.
<h:outputText value="#{paymentBill.amount}" >
<f:convertNumber pattern="#0.00" />
</h:outputText>
If it's <h:outputText> then you can use arbitrary EL expression as its value, if you're so dissatisfied with getting absolute value while preparing data in your managed bean, as it's rightly proposed by perissf and fareed, like:
value="#{(paymentBill.amount lt 0) ? -paymentBill.amount : paymentBill.amount}"
You can return the absolute value of the amount In the backing bean.
Return Math.abs(amount) instead of amount.

How do I set a selectiOneRadioButton-value inside an ui:repeat depending on the iterated entity?

in my usecase I have a (Primefaces) selectOneRadio. This is within an ui:repeat. Values of selectOneRadio are displayed fine. I want each selectOneRadio to have a useful default-value, depending on the iterated entity. This works fine, too, default is selected. But with my approach, I am not able to set the value of the selectOneRadio, as an exception rises:
javax.el.PropertyNotWritableException: [...] value="#{orderBean.getProductPriceId(product)}": Illegal Syntax for Set Operation
How do I set a selectiOneRadioButton-value inside an ui:repeat depending on the iterated entity?
OrderBean:
public class OrderBean {
private String productPriceId; // + getter and setter
public String getProductPriceId(final Product product) {
return product == null ? "" : product.getPricesAsList().get(0).getId().toString();
}
}
xhtml:
<ui:repeat var="product" value="...">
<p:selectOneRadio value="#{orderBean.getProductPriceId(product)}">
...
</p:selectOneRadio>
</ui:repeat>
This makes indeed no sense. You need to make sure that the model matches the view without any need for additional business logic.
Just use
<p:selectOneRadio value="#{product.priceId}">
and give the default item a value of null instead of "" so that it matches.

Resources