The following JSF code contains two separate <c:if></c:if>. Let's look at it.
<?xml version='1.0' encoding='UTF-8' ?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
<title>JSF EL</title>
</h:head>
<h:body>
<h:form>
<c:set scope="request" var="row" property="x" value="10"/>
<c:if test="#{row==10}">
<h:outputLabel value="value = 10"/>
</c:if>
<c:if test="#{row==15}">
<h:outputLabel value="value = 15"/>
</c:if>
</h:form>
</h:body>
</html>
It simply displays value=10 on the JSF page at run time. I need to represent the above same <c:if></c:if> with the following if-elseif-else (Java context).
if(row.equals(10))
{
//Do something...(JSF stuff)
}
else if(row.equals(15))
{
//Do something...(JSF stuff)
}
else
{
//Do something...(JSF stuff)
}
How can it be represented with Expression Language (EL) using JSF?
You can use EL if you want to work as IF:
<h:outputLabel value="#{row==10? '10' : '15'}"/>
Changing styles or classes:
style="#{test eq testMB.test? 'font-weight:bold' : 'font-weight:normal'}"
class="#{test eq testMB.test? 'divRred' : 'divGreen'}"
The following code the easiest way:
<h:outputLabel value="value = 10" rendered="#{row == 10}" />
<h:outputLabel value="value = 15" rendered="#{row == 15}" />
<h:outputLabel value="value xyz" rendered="#{row != 15 and row != 10}" />
Link for EL expression syntax.
http://developers.sun.com/docs/jscreator/help/jsp-jsfel/jsf_expression_language_intro.html#syntax
You can use "ELSE IF" using conditional operator in expression language as below:
<p:outputLabel value="#{transaction.status.equals('PNDNG')?'Pending':
transaction.status.equals('RJCTD')?'Rejected':
transaction.status.equals('CNFRMD')?'Confirmed':
transaction.status.equals('PSTD')?'Posted':''}"/>
One possible solution is:
<h:panelGroup rendered="#{bean.row == 10}">
<div class="text-success">
<h:outputText value="#{bean.row}"/>
</div>
</h:panelGroup>
Related
I have lot's of outputLabel and inputText pairs in panelGrids
<h:panelGrid columns="2">
<h:outputLabel value="label1" for="inputId1"/>
<h:inputText id="inputId1/>
<h:outputLabel value="label2" for="inputId2"/>
<h:inputText id="inputId2/>
...
</h:panelGrid>
I want to have some behaviour for all of them: like same validation or same size for every inputText. So I have created a composite component which just includes an outputLabel and and an inputText
<my:editField value="field1"/>
<my:editField value="field2"/>
But now when I put them in a gridPanel, they do not get aligned depending on the length of the label text. I understand why, but I don't know how to work around.
A composite component gets indeed rendered as a single component. You want to use a Facelet tag file instead. It gets rendered exactly as whatever its output renders. Here's a kickoff example assuming that you want a 3-column form with a message field in the third column.
Create tag file in /WEB-INF/tags/input.xhtml (or in /META-INF when you want to provide tags in a JAR file which is to be included in /WEB-INF/lib).
<ui:composition
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<c:set var="id" value="#{not empty id ? id : (not empty property ? property : action)}" />
<c:set var="required" value="#{not empty required and required}" />
<c:choose>
<c:when test="#{type != 'submit'}">
<h:outputLabel for="#{id}" value="#{label} #{required ? '* ' : ''}" />
</c:when>
<c:otherwise>
<h:panelGroup />
</c:otherwise>
</c:choose>
<c:choose>
<c:when test="#{type == 'text'}">
<h:inputText id="#{id}" value="#{bean[property]}" label="#{label}" required="#{required}">
<f:ajax event="blur" render="#{id}-message" />
</h:inputText>
<h:message id="#{id}-message" for="#{id}" />
</c:when>
<c:when test="#{type == 'password'}">
<h:inputSecret id="#{id}" value="#{bean[property]}" label="#{label}" required="#{required}">
<f:ajax event="blur" render="#{id}-message" />
</h:inputSecret>
<h:message id="#{id}-message" for="#{id}" />
</c:when>
<c:when test="#{type == 'select'}">
<h:selectOneMenu id="#{id}" value="#{bean[property]}" label="#{label}" required="#{required}">
<f:selectItems value="#{options.entrySet()}" var="entry" itemValue="#{entry.key}" itemLabel="#{entry.value}" />
<f:ajax event="change" render="#{id}-message" />
</h:selectOneMenu>
<h:message id="#{id}-message" for="#{id}" />
</c:when>
<c:when test="#{type == 'submit'}">
<h:commandButton id="#{id}" value="#{label}" action="#{bean[action]}" />
<h:message id="#{id}-message" for="#{id}" />
</c:when>
<c:otherwise>
<h:panelGroup />
<h:panelGroup />
</c:otherwise>
</c:choose>
</ui:composition>
Define it in /WEB-INF/example.taglib.xml (or in /META-INF when you want to provide tags in a JAR file which is to be included in /WEB-INF/lib):
<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
version="2.0">
<namespace>http://example.com/jsf/facelets</namespace>
<tag>
<tag-name>input</tag-name>
<source>tags/input.xhtml</source>
</tag>
</facelet-taglib>
Declare the taglib usage in /WEB-INF/web.xml (this is not needed when the tags are provided by a JAR file which is included in /WEB-INF/lib! JSF will auto-load all *.taglib.xml files from /META-INF).
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/example.taglib.xml</param-value>
</context-param>
(multiple taglib files can be separated by semicolon ;)
Finally just declare it in your main page templates.
<!DOCTYPE html>
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:my="http://example.com/jsf/facelets"
>
<h:head>
<title>Facelet tag file demo</title>
</h:head>
<h:body>
<h:form>
<h:panelGrid columns="3">
<my:input type="text" label="Username" bean="#{bean}" property="username" required="true" />
<my:input type="password" label="Password" bean="#{bean}" property="password" required="true" />
<my:input type="select" label="Country" bean="#{bean}" property="country" options="#{bean.countries}" />
<my:input type="submit" label="Submit" bean="#{bean}" action="submit" />
</h:panelGrid>
</h:form>
</h:body>
</html>
(the #{bean.countries} should return a Map<String, String> with country codes as keys and country names as values)
Screenshot:
Hope this helps.
There should have been a switch in panelGrid to render composite components separately. I have a solution for this. You can have separate composite components instead of clubbing them together. In each composite component you can use ui:fragments to demarcate the components you want to separately fall under different columns. Following is extract from my inputText.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:ui="http://java.sun.com/jsf/facelets">
<composite:interface>
<composite:attribute name="id" />
<composite:attribute name="value" />
<composite:attribute name="label" />
<composite:attribute name="readonly" />
<composite:attribute name="disabled" />
<composite:attribute name="required" />
</composite:interface>
<composite:implementation>
<ui:fragment id="label">
<h:outputText id="#{cc.attrs.id}Label" value="#{cc.attrs.label}"
for="#{cc.attrs.id}" />
<h:outputLabel value="#{bundle['label.STAR']}"
rendered="#{cc.attrs.required}" styleClass="mandatory"
style="float:left"></h:outputLabel>
<h:outputLabel value=" " rendered="#{!cc.attrs.required}"
styleClass="mandatory"></h:outputLabel>
</ui:fragment>
<ui:fragment id="field">
<h:inputText id="#{cc.attrs.id}" value="#{cc.attrs.value}"
styleClass="#{not component.valid ? 'errorFieldHighlight medium' : 'medium'}"
disabled="#{cc.attrs.disabled}" required="#{cc.attrs.required}"
label="#{cc.attrs.label}" readonly="#{cc.attrs.readonly}">
</h:inputText>
</ui:fragment>
</composite:implementation>
</html>
Now this will not going to align in the form which is inside the panelGrid:
<h:panelGrid width="100%">
<my:inputText label="#{bundle['label.fname']}" value="#{bean.fname}" id="fname"></my:inputtext>
<my:inputText label="#{bundle['label.lname']}" value="#{bean.lname}" id="lname"></my:inputtext>
</panelGrid>
So i have extended the GroupRenderer's encodeRecursive method, to add after label and a before field:
// inside my extended renderer
protected void encodeRecursive(FacesContext context, UIComponent component)
throws IOException {
// Render our children recursively
if (component instanceof ComponentRef
&& component.getId().equals("field")) {
context.getResponseWriter().startElement("td", component);
}
super.encodeRecursive(context, component);
if (component instanceof ComponentRef
&& component.getId().equals("label")) {
context.getResponseWriter().endElement("td");
}
}
I'm trying the following aprouch to display a date-based chart with primefaces:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<ui:composition template="/template/menu.xhtml">
<ui:define name="content">
<h:form>
<p:dataTable value="#{busca.resultado}" var="serie" style="width:1000px">
<p:column>
<h:panelGrid columns="3" rows="2">
<h:outputText value="#{serie.tipoEmTexto()}" />
<h:outputText value="#{serie.nome}" />
<h:commandButton value="#{busca.controle[busca.resultado.indexOf(serie)] ? 'X' : '+'}" action="#{busca.flip()}">
<f:attribute name="serPar" value="#{serie}" />
<f:ajax render="'serie_'.concat(#{busca.resultado.indexOf(serie)})" event="click" />
</h:commandButton>
<h:panelGroup id="serie_#{busca.meuIndice()}" >
<f:attribute name="serPar" value="#{serie}" />
<h:panelGrid rendered="#{busca.meuControle()}" columns="2">
<f:attribute name="serPar" value="#{serie}" />
<h:outputLabel value="Extrair" />
<h:selectBooleanCheckbox value="#{serie.selecionado}" />
<h:outputLabel value="Série #{serie.periodicidadeComoTexto()}" />
<br />
<p:chart type="line" model="#{busca.graficoReal[busca.resultado.indexOf(serie)]}" style="height:300px;width:400px;" responsive="true"/>
</h:panelGrid>
</h:panelGroup>
</h:panelGrid>
</p:column>
</p:dataTable>
</h:form>
</ui:define>
</ui:composition>
</html>
However, whenever "busca.flip()" is activated and the panelGroup is rendered, no graph is rendered: it simply shows as a blank. This is the creation of the LineChartModel object:
private void carregaGraficoReal(Serie s, int index)
{
int i;
LineChartSeries lcs = new LineChartSeries("Gráfico para " + s.getNome());
LineChartModel lcm = new LineChartModel();
List<String> ls = new ArrayList<String>();
DateAxis da = new DateAxis("Datas");
String data;
ls.addAll(s.getSerieReal().keySet());
ls = OrdenadoresDeLista.ordenaDatas(ls);
for(i = 0; i < ls.size(); i++)
{
data = ls.get(i);
lcs.set(dataParaFormatoPrime(data), s.getSerieReal().get(data));
}
da.setMax(ls.get(ls.size() - 1));
da.setTickAngle(-50);
da.setTickFormat("%b %#d, %y");
lcm.addSeries(lcs);
lcm.getAxis(AxisType.Y).setLabel("Valores");
lcm.getAxes().put(AxisType.X, da);
graficoReal[index] = lcm;
}
For me, at least, it seem to be all in order with what is stabilished in the showcase, so I don't have a clue of why it isn't working. I'm running this application in a App Server Glassfish 4.0, JDK 1.7.0, primefaces 5.1 and using JSF 2, if this information might help someone pinpoint why the graph isn't being rendered.
A bit of more information about my code:
ordenaDatas return a list of strings, which are dates, ordered in crescent order;
dataParaFormatoPrime turns a string of type "dd/mm/YYYY" in the format "YYYY-mm-dd", as showed in the showcase;
The panelGroup "serie_x" is rendered correctly for each item of p:dataTable, only not showing the graph;
I have 2 Facelets files (index.xhtml and report.xhtml). I use the RichFaces <ui:include src="report.xhtml"/> to load the report into the index. Works fine.
But when I try to only show report on certain conditions, I fail! What does not work is this:
<ui:include src="report.xhtml" rendered="#{indexService.contentName == 'report'}"/>.
The rendered attribute of ui:include does not seem to work.
How can I load the report.xhtml into the index.xhtml on certain conditions? Where is the error in my code?
Edit:
Half of it works now. Changing the Facelet file works with conditions. But the functionality of the loaded Facelet does not work properly. Why is that? Where is the problem in the code?
Based on the suggestions I now have this:
<h:form>
<h:panelGrid>
<a4j:commandLink value="Home" render="contentpanel" action="#{indexService.setContentName('home')}"/>
<a4j:commandLink value="Report" render="contentpanel" action="#{indexService.setContentName('report')}"/>
</h:panelGrid>
</h:form>
<a4j:outputPanel id="contentpanel">
<ui:fragment rendered="#{indexService.contentName eq 'report'}">
<ui:include src="report.xhtml" />
</ui:fragment>
</a4j:outputPanel>
Edit 2:
This is my report Facelet. If I use without any condition the functionality of the report Facelet works perfectly, but if I load it using the condition I posted in Edit 1, then the buttons of <rich:panelMenuItem .../> don't work anymore and <h:outputText escape="false" value="#{reportService.content}"/> does not load the content. Any idea why?
Edit 3:
Changed the <rich:panel header="Report">...</rich:panel>, but behaviour still unchanged.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:rich="http://richfaces.org/rich"
xmlns:a4j="http://richfaces.org/a4j">
<ui:composition>
<h:outputStylesheet>
.placesmenu {
width: 200px;
vertical-align: top;
}
.contentplace {
vertical-align: top;
}
</h:outputStylesheet>
<h:panelGrid columns="2" width="100%" columnClasses="placesmenu, contentplace">
<rich:panel header="Places">
<h:form>
<rich:panelMenu style="width: 170px">
<a4j:repeat value="#{reportService.menuItems}" var="menuItem" id="repeat_layer1">
<rich:panelMenuGroup label="#{menuItem.label}">
<a4j:repeat value="#{menuItem.subMenuItemList}" var="subMenuItem" id="repeat_layer2">
<rich:panelMenuItem label="#{subMenuItem.label}" render="reportpanel" onbeforedomupdate="#{reportService.setId(subMenuItem.id)}"/>
</a4j:repeat>
</rich:panelMenuGroup>
</a4j:repeat>
</rich:panelMenu>
</h:form>
</rich:panel>
<rich:panel header="Report">
<h:outputText escape="false" value="#{reportService.content}" id="reportpanel"/>
</rich:panel>
</h:panelGrid>
</ui:composition>
</html>
try to surround your ui:include tag with ui:fragment as follows :-
<ui:fragment rendered="#{indexService.contentName eq 'report'}">
<ui:include src="report.xhtml" />
</ui:fragment>
<?xml version="1.0" encoding="UTF-8"?>
<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<f:view>
<h:head>
<title>Admin Welcome</title>
<!-- this is the javascript part! -->
<script>
function validateForm()
{
if(document.form.firstname.value=="" || document.form.lastname.value=="" || document.form.mobileno.value=="")
{
alert("first/lastname/mobile number should not be left blank");
document.userreg.fname.focus();
return false;
}
if(!isNaN(document.form.firstname.value) || !isNaN(document.form.lastname.value) )
{
alert("Please Enter Only Characters for first/last names");
return false;
}
if(isNaN(document.form.mobileno.value))
{
alert("please enter only Numbers for mobile number")
return false;
}
}
</script>
</h:head>
<h:body>
Welcome admin!
<center><h1>User Registration Form</h1></center>
<center><h:form id="form">
<p:panel id="panel">
<p:messages id="msgs"/>
<h:panelGrid columns="3" >
<h:panelGroup>
<h:outputLabel for="firstname" value="firstname: *" />
<p:inputText id="firstname" value="#{userBean.firstname}" required="true" label="firstname">
</p:inputText>
<br></br> <br></br>
<h:outputLabel for="lastname" value="lastname: *" />
<p:inputText id="lastname" value="#{userBean.lastname}" label="lastname" required="true">
</p:inputText>
<br></br><br></br>
<h:outputLabel for="mobileno" value="mobileno: *" />
<p:inputText id="mobileno" value="#{userBean.mobileno}" label="mobileno" required="true">
</p:inputText>
</h:panelGroup>
</h:panelGrid>
<br></br>
<p:commandButton ajax="false" id="btn" value="submit" type='submit' onclick="return validateForm()" />
<p:commandButton value="reset" type="reset" />
</p:panel>
</h:form></center>
</h:body>
</f:view>
</html>
the javascript part is not getting executed. why?
To strictly answer your question, check the javascript error console. One of the error messages that you will see is the following (from FireFox on my end).
TypeError: document.form.firstname is undefined
The easiest way to fix your issue is to add prependId="false" in your <h:form>.
If you do not like the prependId = "false" approach, you could also change
document.form.firstname
to
document.form["form" + ":" + "firstname"].value
This will need to be done throughout your Javascript method, so keep this in mind.
Remember that your components id such as p:inputText id="firstname"... for example will have the following pattern formId:componentId. It would then be form:firstname. Of course this is a simplified explanation and this may not always be the case. For more information please refer to
How can I know the id of a JSF component so I can use in Javascript
Also, the easiest way to determine component id is to simply view the HTML code (right click > View Page Source).
<f:view> is really not needed in your case, (unless there's more we're not seeing of course). Like erencan suggested refer to this link also
When to use f:view and f:subview
Popup panels in RichFaces are pretty ugly to work with to be honest. There are several calls to some JavaScripts involved which makes it not easy to derive something that works in general. Anyway, I was trying the following:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<h:commandLink>
<h:graphicImage library="images/icons" name="#{buttonImageFileName}" />
<rich:tooltip value="#{buttonTooltipText}" direction="bottomRight" />
<rich:componentControl target="#{popupId}" operation="show" />
</h:commandLink>
<rich:popupPanel modal="true"
height="#{popupHeight}"
resizeable="#{popupResizable}"
onmaskclick="#{componentCallToId}.hide(); return false;"
id="#{popupId}">
<f:facet name="header">
<h:outputText value="#{popupHeaderText}" />
</f:facet>
<f:facet name="controls">
<h:outputLink value="#" onclick="#{componentCallToId}.hide(); return false;">
<h:outputText value="X" />
</h:outputLink>
</f:facet>
<p>#{popupSubject}</p>
<p>
<h:inputText value="#{inputTextBean[inputTextProperty]}" styleClass="full-width" id="#{inputTextId}" />
</p>
<h:panelGrid columns="2" style="margin: 0 auto;">
<h:commandButton value="OK"
action="#{acceptButtonBean[acceptButtonMethod](acceptButtonMethodArg)}"
onclick="#{componentCallToId}.hide(); return true;">
<a4j:ajax execute="#this #{inputTextId}" render="#form" />
</h:commandButton>
<h:commandButton value="Cancel" onclick="#{componentCallToId}.hide(); return false;" immediate="true" />
</h:panelGrid>
</rich:popupPanel>
</ui:composition>
This displays an image button which pops up a simple input dialog, which is supposed to be hidden by clicking outside the popup (onmaskclick="..."), by X'ing the popup in the top right corner (<f:facet> with onclick="..."), or by pressing the Cancel <h:commandButton onclick="...">. On OK the AJAX form is supposed to be submitted and the popup is hidden, too. But nothing happens (can't close):
The EL expression #{componentCallToId}.hide(); return false; is the "problem child" in the above. It is not working that way.
In its original, non-Facelets variant here (http://showcase.richfaces.org/richfaces/component-sample.jsf?demo=popup&sample=modalPopup&skin=classic) the call to control the component looks like this:
<h:commandButton value="Cancel" onclick="#{rich:component('add-root-chapter-popup')}.hide(); return false;" immediate="true" />
I pass the following parameters to <ui:include>:
<ui:include src="/subviews/add-node-clink-input-popup.xhtml">
<ui:param name="buttonImageFileName" value="add.png" />
...
<ui:param name="popupId" value="add-root-chapter-popup" />
<ui:param name="componentControlCallToId" value="rich:component('add-root-chapter-popup')" />
...
</ui:include>
Notice the long entry (the rest seems to be working - even the strange syntax for the bean + method + arg, but this is not the focus here).
Q:
Why isn't <ui:param name="componentControlCallToId" value="rich:component('add-root-chapter-popup')" /> working? Currently nothing happens when clicking outside the popup, X'ing, or pressing OK or Cancel (popup staying).
Firebug only shows:
syntax error
.hide(); return false;
Looks like the expression is evaluated to null/empty string.
What's wrong? Can it be fixed? What are my alternatives?
PS: Note, that I've previously tried to use the "popupId" in the Facelets expression like
<h:commandButton value="Cancel" onclick="#{rich:component('popupId')}.hide(); return false;" immediate="true" />
but this has the same result.
Omitting the single quotes did the trick:
<h:commandButton value="Cancel" onclick="#{rich:component(popupId)}.hide(); return false;" immediate="true" />
I thought they were part of JS, but they seem to be EL here.
Also you could try this:-
onmaskclick="#{rich:component('cc.attrs.popupId')}.hide()"
If the quotes cause you any problem use " instead of them.
I believe here you are trying to parse the id to the popup panel dynamically through your custom components exposed variables.
Where in you might be parsing the value for id as
popupId="xyz"
If this being the situation the above solution would work just fine.