Using JSTL function in JSF - jsf

i want to use the JSTL function contains in JSF2
here's what i tried but the condition always evaluates to false, i think i am missing something:
<c:forEach items="#{myBean.toSendCheckBoxes}" var="entry" varStatus="loop">
<input type="checkbox" name="myArray" value="#{entry.value}" />
<c:choose>
<c:when test="#{fn:contains(entry.key,'g')}">
<ice:graphicImage url="/resources/images/image1.bmp" />
<b>#{entry.key}</b>
</c:when>
<c:otherwise>
<ice:graphicImage url="/resources/images/image2.bmp" />
<span>#{entry.key}</span>
</c:otherwise>
</c:choose>
</c:forEach>
if there's another JSF way to accomplish that, would be very nice to mention it, thanks in advance.

More JSFish way to do it would be
<ui:repeat value="#{myBean.toSendCheckBoxes}" var="entry" varStatus="loop">
<input type="checkbox" name="myArray" value="#{entry.value}" />
<ui:fragment rendered="#{fn:contains(entry.key,'g')}">
<ice:graphicImage url="/resources/images/image1.bmp" />
<b>#{entry.key}</b>
</ui:fragment>
<ui:fragment rendered="#{!fn:contains(entry.key,'g')}">
<ice:graphicImage url="/resources/images/image2.bmp" />
<span>#{entry.key}</span>
</ui:fragment>
</ui:repeat>
or even
<ui:repeat value="#{myBean.toSendCheckBoxes}" var="entry" varStatus="loop">
<input type="checkbox" name="myArray" value="#{entry.value}" />
<ice:graphicImage url="#{fn:contains(entry.key,'g') ? '/resources/images/image1.bmp' : '/resources/images/image2.bmp'}" />
<span class="#{fn:contains(entry.key,'g') ? 'bold-style' : ''}">#{entry.key}</span>
</ui:repeat>
but I would expect your condition to evaluate properly nevertheless.

I use t:dataList (myfaces tomahawk xmlns:t="http://myfaces.apache.org/tomahawk") for looping over elements to have correct identifier generation and rendered attribute for different displaying of elements in the list.
<t:dataList layout="simple" value="#{myBean.toSendCheckBoxes}" var="entry">
<input type="checkbox" name="myArray" value="#{entry.value}" />
<h:panelGroup rendered="#{fn:contains(entry.key,'g')}">
<ice:graphicImage url="/resources/images/image1.bmp" />
<b>#{entry.key}</b>
</h:panelGroup>
<h:panelGroup rendered="#{not fn:contains(entry.key,'g')}">
<ice:graphicImage url="/resources/images/image2.bmp" />
<span>#{entry.key}</span>
</h:panelGroup>
</t:dataList>
I've had issues with dynamic element rendering (show/hide rows) within ui:repeat, so I had to use t:dataList instead.

Related

jstl request performance

I have some objects in a list witch are components and I implemented this to show them :
first.xhtml:
<h:form id="sceneForm">
<c:forEach items="#{templateController.model.selectedTemplate.templatesSet.toArray()}" var="templateControls" varStatus="ind">
<ui:include src="second.xhtml"/>
</c:forEach>
</h:form>
second.xhtml:
<c:forEach items="#{templateControls.controlAttributes.toArray()}" var="controlAttributes" >
<c:choose>
<c:when test="#{controlAttributes.controlAttributeType.name == 'top'}">
<ui:param name="top" value="#{controlAttributes.value}px" />
</c:when>
<c:when test="#{controlAttributes.controlAttributeType.name == 'left'}">
<ui:param name="left" value="#{controlAttributes.value}px" />
</c:when>
<c:when test="#{controlAttributes.controlAttributeType.name == 'width'}">
<ui:param name="width" value="#{controlAttributes.value}px" />
</c:when>
<c:when test="#{controlAttributes.controlAttributeType.name == 'height'}">
<ui:param name="height" value="#{controlAttributes.value}" />
</c:when>
</c:choose>
</c:forEach>
<c:if test="#{templateControls.controlType.type == 'Button'}">
<div style="top:#{top}; left:#{left}; width:#{width}; height:#{height}px;>
<div class="gui-component-inner">
<span>#{value}</span>
<em class="helper"></em>
</div>
</div>
</c:if>
I iterate throught my attributes list and I set some variables and after it I set my component with variables. This works fine but it is not optim. I make a button:
<p:commandButton value="Test" actionListener="#{templateController.testAction}" onstart="Utils.PrintTime()" oncomplete="Utils.PrintTime()"/>
Witch prints the time on request start and on request end, and it takes 2 second if, if I delete the whole <c:forEach> then it takes 0,05 seconds. How could I make a better request time with iteration? Any idea?
Why I get that minus I don`t know...
Also here is my solution:
I make an object with top,left,width,height and declared it in the TemplateControl object. On page load I iterate the templateControls.controlAttributes and I set top,left,width,height for each component. And in xhtml I simply write:
<c:if test="#{templateControls.controlType.type == 'Button'}">
<div style="top:#{templateControls.atr.top}; left:#{templateControls.atr.left}; width:#{templateControls.atr.width}; height:#{templateControls.atr.height}px;>
<div class="gui-component-inner">
<span>#{value}</span>
<em class="helper"></em>
</div>
</div>
</c:if>
Like this I make my iteration in java at the beginning and not in xhtml and I freed from the <c:forEach> and <c:if> tags and now my requests are very fast.

Customize attribute of one panel id of Composite component .in JSF2,2 [duplicate]

I am writing a composite component that is intended to wrap an input element, and augment it with an 'optional field' designation and h:message element below it.
Here is the component (in input.xhtml file):
<composite:interface/>
<composite:implementation>
<div>
#{component.children[1].setStyleClass(component.children[1].valid ? '' : 'inputError')}
<composite:insertChildren/>
</div>
<h:panelGroup styleClass="optional"
rendered="#{!component.parent.children[1].required}"
layout="block" >
#{msgs['common.optional.field']}
</h:panelGroup>
<h:message id="msgId"
for="#{component.parent.children[1].id}" errorClass="error"/>
</composite:implementation>
Again, the intended usage of the component is to wrap an h:input* element which is expected to be the first and immediate child of it in a using page.
In a using page I would then write:
<h:form id="f1">
<h:panelGrid border="0" columns="2" style="width: 80%">
<f:facet name="header">
<col width="40%" />
<col width="60%" />
</f:facet>
<h:outputLabel styleClass="sectionBody" for="i1"
value="Input 1"></h:outputLabel>
<my:input id="ii1">
<h:inputText id="i1" size="20" maxlength="20" tabindex="0"
required="true" label="Input 1">
</h:inputText>
</my:input>
<h:outputLabel styleClass="sectionBody" for="i2"
value="Input 2"></h:outputLabel>
<my:input id="ii2">
<h:inputText id="i2" size="20" maxlength="20" tabindex="0"
label="Input 2">
</h:inputText>
</my:input>
</h:panelGrid>
<br />
<h:commandButton value="Submit" tabindex="1">
<f:ajax listener="#{terminalImportBean.addTerminal}"
execute="#form" render="#form"/>
</h:commandButton>
</h:form>
This would work just fine using normal posts.
However if I add add f:ajax validation for "Input 1" (id="i1") and try to re-render the composite (ii1) using the following:
...
<h:outputLabel styleClass="sectionBody" for="i1"
value="Input 1"></h:outputLabel>
<my:input id="ii1">
<h:inputText id="i1" size="20" maxlength="20" tabindex="0"
required="true" label="Input 1">
<f:ajax listener="#{myBean.checkInput1}"
event="blur"
render="ii1"/>
</h:inputText>
</my:input>
...
I gen an error in the browser during ajax response processing:
malformedXML: During update: f1:ii1 not found
I tried using f1:ii1, :f1:ii1, but to no avail. When I use msgId or :f1:ii1:msgId it works. Does anybody know why?
I am using Mojarra 2.1.3
Thanks
That's because the composite component does by itself not render anything to the HTML. Only its children are been rendered to HTML. There does not exist any HTML element with ID f1:i11 in the generated HTML output. Open the page in browser, rightclick and View Source. Look in there yourself. There's no such element with that ID. JavaScript/Ajax is encountering exactly the same problem. It can't find the element in order to update it.
To solve this, you'd need to wrap the entire composite body in a HTML <div> or <span> and assign it an ID of #{cc.clientId} which basically prints UIComponent#getClientId().
<cc:implementation>
<div id="#{cc.clientId}">
...
</div>
</cc:implementation>
Then you can reference it as below:
<my:input id="foo" />
...
<f:ajax ... render="foo" />
You can even reference a specific composite component child.
<f:ajax ... render="foo:inputId" />
See also:
Is it possible to update non-JSF components (plain HTML) with JSF ajax?
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"

t:selectOneRadio with a4j:ajax no javascript rendered

I'm creating a dynamic form with radio buttons in front of each rows that need to update a cart when a different row is selected :
<t:inputText id="test">
<f:ajax event="click" onevent="alert('3');" />
</t:inputText>
<t:selectOneRadio id="rbtnQuantity" value="#{orderActions.selectedQuantity}" layout="spread">
<f:selectItems value="#{orderActions.quantities}" var="item" />
<f:converter converterId="integerConverter" />
<a4j:ajax event="click" oncomplete="renderPrices();" />
</t:selectOneRadio>
<rich:dataTable id="tblQuantities" styleClass="quantities" value="#{orderActions.formatQuantityPrices}" var="item" rowKeyVar="row">
<h:column>
<t:radio id="rbtnQuantity" for=":form:rbtnQuantity" index="#{row}" />
</h:column>
<h:column>
<h:outputText value="#{item.quantity}" />
</h:column>
<h:column>
<h:outputText value="#{item.price}">
<f:convertNumber type="currency" currencySymbol="$" />
</h:outputText>
</h:column>
<h:column>
<h:outputText value="#{item.price / item.quantity}">
<f:convertNumber type="currency" currencySymbol="$" />
</h:outputText>/u
</h:column>
</rich:dataTable>
The problem is that no radio button fire the ajax event, even no javascript code is rendered in the resuling code :
<table id="form:tblQuantities" class="rf-dt quantities">
<colgroup span="4">
</colgroup>
<tbody id="form:tblQuantities:tb" class="rf-dt-b">
<tr id="form:tblQuantities:0" class="rf-dt-r rf-dt-fst-r">
<td id="form:tblQuantities:0:j_idt296" class="rf-dt-c">
<label><input id="form:tblQuantities:0:rbtnQuantity" type="radio" name="form:rbtnQuantity" checked="checked" value="25" /> 25</label>
</td>
<td id="form:tblQuantities:0:j_idt297" class="rf-dt-c">25</td>
<td id="form:tblQuantities:0:j_idt309" class="rf-dt-c">118,75 $</td>
<td id="form:tblQuantities:0:j_idt310" class="rf-dt-c">4,75 $/u</td>
</tr>
[more similar rows...]
I've also included one t:inputText at top, see if it was the t:selectOneRadio usage that was the problem but no.
I'm using Mojarra, RichFaces 4.2.1, Tomahawk 1.1.14.
Since I've not been able to use a4j:ajax or f:ajax with t:selectOneRadio, I've used this workaround :
<a4j:jsFunction name="changeQuantity" oncomplete="renderPrices();">
<a4j:param assignTo="#{orderActions.selectedQuantity}" name="quantity" />
</a4j:jsFunction>
<t:selectOneRadio onclick="quantity = jQuery(this).val();changeQuantity(quantity);" id="rbtnQuantity" value="#{orderActions.selectedQuantity}" layout="spread">
<f:selectItems value="#{orderActions.quantities}" var="item" />
<f:converter converterId="integerConverter" />
</t:selectOneRadio>
It is working properly, but I would prefer to fix the problem if ever someone find the right solution or I.
EDIT :
Here is the final used code :
<a4j:jsFunction name="changeQuantity" oncomplete="renderPrices();">
<a4j:param assignTo="#{orderActions.selectedQuantity}" name="quantity" />
</a4j:jsFunction>
# Each row of the table :
<input type="radio" name="quantity" value="#{item.quantity}" checked="#{orderActions.selectedQuantity eq item.quantity ? 'checked' : ''}" onclick="changeQuantity(#{item.quantity});" />

Referring composite component ID in f:ajax render

I am writing a composite component that is intended to wrap an input element, and augment it with an 'optional field' designation and h:message element below it.
Here is the component (in input.xhtml file):
<composite:interface/>
<composite:implementation>
<div>
#{component.children[1].setStyleClass(component.children[1].valid ? '' : 'inputError')}
<composite:insertChildren/>
</div>
<h:panelGroup styleClass="optional"
rendered="#{!component.parent.children[1].required}"
layout="block" >
#{msgs['common.optional.field']}
</h:panelGroup>
<h:message id="msgId"
for="#{component.parent.children[1].id}" errorClass="error"/>
</composite:implementation>
Again, the intended usage of the component is to wrap an h:input* element which is expected to be the first and immediate child of it in a using page.
In a using page I would then write:
<h:form id="f1">
<h:panelGrid border="0" columns="2" style="width: 80%">
<f:facet name="header">
<col width="40%" />
<col width="60%" />
</f:facet>
<h:outputLabel styleClass="sectionBody" for="i1"
value="Input 1"></h:outputLabel>
<my:input id="ii1">
<h:inputText id="i1" size="20" maxlength="20" tabindex="0"
required="true" label="Input 1">
</h:inputText>
</my:input>
<h:outputLabel styleClass="sectionBody" for="i2"
value="Input 2"></h:outputLabel>
<my:input id="ii2">
<h:inputText id="i2" size="20" maxlength="20" tabindex="0"
label="Input 2">
</h:inputText>
</my:input>
</h:panelGrid>
<br />
<h:commandButton value="Submit" tabindex="1">
<f:ajax listener="#{terminalImportBean.addTerminal}"
execute="#form" render="#form"/>
</h:commandButton>
</h:form>
This would work just fine using normal posts.
However if I add add f:ajax validation for "Input 1" (id="i1") and try to re-render the composite (ii1) using the following:
...
<h:outputLabel styleClass="sectionBody" for="i1"
value="Input 1"></h:outputLabel>
<my:input id="ii1">
<h:inputText id="i1" size="20" maxlength="20" tabindex="0"
required="true" label="Input 1">
<f:ajax listener="#{myBean.checkInput1}"
event="blur"
render="ii1"/>
</h:inputText>
</my:input>
...
I gen an error in the browser during ajax response processing:
malformedXML: During update: f1:ii1 not found
I tried using f1:ii1, :f1:ii1, but to no avail. When I use msgId or :f1:ii1:msgId it works. Does anybody know why?
I am using Mojarra 2.1.3
Thanks
That's because the composite component does by itself not render anything to the HTML. Only its children are been rendered to HTML. There does not exist any HTML element with ID f1:i11 in the generated HTML output. Open the page in browser, rightclick and View Source. Look in there yourself. There's no such element with that ID. JavaScript/Ajax is encountering exactly the same problem. It can't find the element in order to update it.
To solve this, you'd need to wrap the entire composite body in a HTML <div> or <span> and assign it an ID of #{cc.clientId} which basically prints UIComponent#getClientId().
<cc:implementation>
<div id="#{cc.clientId}">
...
</div>
</cc:implementation>
Then you can reference it as below:
<my:input id="foo" />
...
<f:ajax ... render="foo" />
You can even reference a specific composite component child.
<f:ajax ... render="foo:inputId" />
See also:
Is it possible to update non-JSF components (plain HTML) with JSF ajax?
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"

Can EL value pass one to another in JSF and Facelets?

I would like to pass the EL one JSF page to Facelets template. Facelets template just understand EL value as string value. How can I pass EL String to Faceltes Template?
page1.xthml
<ui:include ..../>
<ui:param actionBeanMethod="#{EmployeeActionBean.deleteEmplayee(emp)}>
page2.xthml
<ui:include ..../>
<ui:param actionBeanMethod="#{DepartmentActionBean.deleteDepartment(dep)}>
In comfirmationTemplate.xml
<a4j:commandLink onclick="#{rich:component('confirmation')}.show();return false">
<h:graphicImage value="/img/delete.png" />
</a4j:commandLink>
<a4j:jsFunction name="submit" action="#{actionBeanMethod}"/>
<rich:popupPanel id="confirmation" width="250" height="150">
<f:facet name="header">Confirmation</f:facet>
<h:panelGrid>
<h:panelGrid columns="2">
<h:graphicImage value="/img/alert.png" />
<h:outputText value="Are you sure?" style="FONT-SIZE: large;" />
</h:panelGrid>
<h:panelGroup>
<input type="button" value="OK" onclick="#{rich:component('confirmation')}.hide();submit();return false" />
<input type="button" value="Cancel" onclick="#{rich:component('confirmation')}.hide();return false" />
</h:panelGroup>
</h:panelGrid>
</rich:popupPanel>
I would like to change action of a4j:jsFuction dynamically.
When page1.xhtm is call,
<a4j:jsFunction name="submit" action="#{EmployeeActionBean.deleteEmplayee(emp)"/>
When page2.xhtm is call,
<a4j:jsFunction name="submit" action="#{DepartmentActionBean.deleteDepartment(dep)"/>
Can it possible?
You can't pass method expressions as <ui:param> value. It accepts only value expressions.
You basically need to create a custom taghandler which re-interprets the value expression as a method expression. From the current open source JSF component/utility libraries, the OmniFaces <o:methodParam> is the only one which does exactly that.
<o:methodParam name="methodParam" value="#{actionBeanMethod}" />
<a4j:jsFunction name="submit" action="#{methodParam}" />
You only need to register the Facelets include as a Facelets tag file and use it as
<my:confirmationTemplate actionBeanMethod="#{EmployeeActionBean.deleteEmplayee(emp)}" />
An alternative is to use a composite component instead.

Resources