Bindings in c:forEach - jsf

I have a collection of items which each have a min, likely, and max value. There are validators to ensure the maximum is greater than the minimum etc. The validators use bindings so they can compare all three values the user has entered. Originally they were in a ui:repeat, but that was causing trouble with a dropdown and I found switching to a c:forEach fixed it. Unfortunately, it's also messed up the bindings. I'm hoping there's a way to fix them without going back to the ui:repeat.
Is it possible to have a binding in a c:forEach? Is there some way to add an id or a varStatus index to the binding so it isn't the same for every item in the list? e.g. in the example below I've tried things like
<h:inputText id="impactMin_#{impact.id}" binding="#{impactMin_#{impact.id}}">
<h:inputText id="impactMin_#{impact.id}" binding="#{impactMin}_#{impact.id}">
but unsurprisingly, those don't work. If anyone knows a sensible way of doing this, I'd be very grateful to hear it.
This is a simplified version of the code:
<c:forEach id="impacts" var="impact" items="#{mybean.impacts}" varStatus="i">
<h:panelGroup layout="block" id="impactContainer_#{impact.id}">
<h:outputText value="#{impact.score_impact_type_idInterface.score_impact_type_name}"/>
<h:panelGroup layout="block" class="row form-group" id="impactAssessment_#{impact.id}">
<h:panelGroup layout="block">
<h:inputText id="impactMin" value="#{impact.current_impact_min}" binding="#{impactMin}" label="Minimum">
<f:attribute name="impactMl" value="#{impactMl}"/>
<f:attribute name="impactMax" value="#{impactMax}"/>
<f:convertNumber locale="#{loginInfo.realLocale}" minIntegerDigits="1" maxFractionDigits="2" />
<f:validator binding="#{impactMinValidator}"/>
</h:inputText>
</h:panelGroup>
<h:panelGroup layout="block">
<h:inputText id="impactMl" value="#{impact.current_impact_ml}" binding="#{impactMl}" label="Most likely">
<f:attribute name="impactMin" value="#{impactMin}"/>
<f:attribute name="impactMax" value="#{impactMax}"/>
<f:convertNumber locale="#{loginInfo.realLocale}" minIntegerDigits="1" maxFractionDigits="2" />
<f:validator binding="#{impactLikelyValidator}"/>
</h:inputText>
</h:panelGroup>
<h:panelGroup layout="block">
<h:inputText id="impactMax" value="#{impact.current_impact_max}" binding="#{impactMax}" label="Maximum">
<f:attribute name="impactMin" value="#{impactMin}"/>
<f:attribute name="impactMl" value="#{impactMl}"/>
<f:convertNumber locale="#{loginInfo.realLocale}" minIntegerDigits="1" maxFractionDigits="2" />
<f:validator binding="#{impactMaxValidator}"/>
</h:inputText>
</h:panelGroup>
<div class="col-sm-12">
<h:message for="impactMin"/>
<h:message for="impactMl"/>
<h:message for="impactMax"/>
</div>
</h:panelGroup>
</h:panelGroup>
</c:forEach>

While trying to get a better understanding of bindings in general, I found this answer JSF 2 composites and binding for validation . While not quite the same thing, I found it could be adapted to a c:forEach like this:
<c:forEach id="impacts" var="impact" items="#{mybean.impacts}" varStatus="i">
<h:panelGroup layout="block" id="impactContainer_#{impact.id}">
<h:outputText value="#{impact.score_impact_type_idInterface.score_impact_type_name}"/>
<h:panelGroup layout="block" class="row form-group" id="impactAssessment_#{impact.id}">
<ui:param name="impactMin" value="impactMin_#{impact.id}" />
<ui:param name="impactMl" value="impactMl_#{impact.id}" />
<ui:param name="impactMax" value="impactMax_#{impact.id}" />
<h:panelGroup layout="block">
<h:inputText id="impactMin_#{impact.id}" value="#{impact.current_impact_min}" binding="#{requestScope[impactMin]}" label="Minimum">
<f:attribute name="impactMl" value="#{requestScope[impactMl]}"/>
<f:attribute name="impactMax" value="#{requestScope[impactMax]}"/>
<f:convertNumber locale="#{loginInfo.realLocale}" minIntegerDigits="1" maxFractionDigits="2" />
<f:validator binding="#{impactMinValidator}"/>
</h:inputText>
</h:panelGroup>
<h:panelGroup layout="block">
<h:inputText id="impactMl_#{impact.id}" value="#{impact.current_impact_ml}" binding="#{requestScope[impactMl]}" label="Most likely">
<f:attribute name="impactMin" value="#{requestScope[impactMin]}"/>
<f:attribute name="impactMax" value="#{requestScope[impactMax]}"/>
<f:convertNumber locale="#{loginInfo.realLocale}" minIntegerDigits="1" maxFractionDigits="2" />
<f:validator binding="#{impactLikelyValidator}"/>
</h:inputText>
</h:panelGroup>
<h:panelGroup layout="block">
<h:inputText id="impactMax_#{impact.id}" value="#{impact.current_impact_max}" binding="#{requestScope[impactMax]}" label="Maximum">
<f:attribute name="impactMin" value="#{requestScope[impactMin]}"/>
<f:attribute name="impactMl" value="#{requestScope[impactMl]}"/>
<f:convertNumber locale="#{loginInfo.realLocale}" minIntegerDigits="1" maxFractionDigits="2" />
<f:validator binding="#{impactMaxValidator}"/>
</h:inputText>
</h:panelGroup>
<div class="col-sm-12">
<h:message for="impactMin_#{impact.id}"/>
<h:message for="impactMl_#{impact.id}"/>
<h:message for="impactMax_#{impact.id}"/>
</div>
</h:panelGroup>
</h:panelGroup>
</c:forEach>
Note the ui:param bits near the top. That seems to do the trick. Thanks BalusC!

Related

Omnifaces validateMultiple not triggered in combination with single field validator

I have a loop for constructing 12 input fields:
<h:panelGroup id="panel">
<c:forEach id="iter" items="#{of:createIntegerArray(0,12)}" var="dVar" varStatus="dLoop">
<h:inputText id="input#{dLoop.index}" value="#{doc['input'+=dLoop.index]}" process="#form:panel" update="#form:panel" />
</c:forEach>
<o:validateMultiple id="validateFields" components="#{controller.componentsString}" validator="#{dValidator}" />
</h:panelGroup>
This works ok, until I put a standard validator on the input field. Then the #{dValidator} is not triggered.
So this is not triggering the validator in o:validateMultiple:
<h:panelGroup id="panel">
<c:forEach id="iter" items="#{of:createIntegerArray(0,12)}" var="dVar" varStatus="dLoop">
<h:inputText id="input#{dLoop.index}" value="#{doc['input'+=dLoop.index]}" process="#form:panel" update="#form:panel">
<o:validator validatorId="javax.faces.Length" minimum="5" />
</h:inputText>
</c:forEach>
<o:validateMultiple id="validateFields" components="#{controller.componentsString}" validator="#{dValidator}" />
</h:panelGroup>
Is this a bug in the library? Is there a workaround?
Thanks.

Unexpected result with h:dataGrid

The underlying code makes the look of two column table while there are four panelGroup's.
<h:panelGrid id="panel" columns="4" border="1" cellpadding="0" cellspacing="2">
<h:panelGroup><h:outputText value="#{ph.currentProduct.brand} #{ph.currentProduct.model}"/>
</h:panelGroup>
<h:panelGroup><h:outputText value="#{ph.currentProduct.price} грн"/>
</h:panelGroup>
<h:panelGroup>
Наличие:
<p:rating id="present" value="#{ph.currentProduct.present}" readonly="true" />
<p:tooltip for="present" value="test" />
</h:panelGroup>
<h:panelGroup>
<h:form id="buy_button" style="">
<h:inputHidden value="#{ph.productId}" />
<h:commandButton image="images/buy.png" action="#{ph.addToCart}" />
</h:form>
</h:panelGroup>
</h:panelGrid>
Why is it?

rich:tooltip does not work in rich:popupPanel

When I attach rich:tooltip element to any element of the screen of rich:popupPanel, it shows nothing. How can I solve this problem?
<rich:popupPanel id="balancePopup" width="800" resizeable="false"
rendered="true" autosized="true" modal="true"domElementAttachment="body">
<a4j:outputPanel id="balancePanelRegion">
<ui:include src="popup.xhtml" />
</a4j:outputPanel>
</rich:popupPanel>
This doesn't work (popup.xhtml)
<h:inputText value=""
id="my" styleClass="input-medium" readonly="true">
<rich:tooltip id="tooltip"><span>Hint</span></rich:tooltip>
</h:inputText>
Increasing z-index of tooltip component solved the problem:
<rich:tooltip id="tooltip3" style="z-index:10000;">Tooltip</rich:tooltip>
Move rich:tooltip outside:
<h:outputText value="Test"/>
<h:panelGroup id="inputWithTooltip">
<h:inputText />
<rich:tooltip mode="client" layout="block">
<h:outputText value="#{msg.info}" escape="false"/>
</rich:tooltip>
</h:panelGroup>

Unable to validate for primefaces event blur?

I am not able to validate input fields using primefaces ajax on the client side by calling event blur using primefaces
<h:panelGrid columns="2">
<p:outputLabel for="uname" value="Name"/>
<p:inputText id="uname" value="#{userbean.name}" required="true" requiredMessage="Enter your name">
<p:ajax event="blur" rendererType="name"/>
</p:inputText>
<h:outputText value=""/>
<p:message id="name" for="uname" />
<p:outputLabel for="add" value="Address"/>
<p:inputText id="add" value="#{userbean.address}" required="true" requiredMessage="Enter your address">
<p:ajax event="blur" rendered="address"/>
</p:inputText>
<h:outputText value=""/>
<p:message id="address" for="add" />
<h:commandButton value="Submit"/>
</h:panelGrid>
I am not sure what you're doing with 'rendererType and rendered' on your ajax events - they make no sense and ikely just breaking.
I've got it working fine in the below example (note my bean is different name) - i made the grid only 1 in colum size just for testing purposes and you're best off wrapping those full data objects you want re-rendered after ajax request. see the below code p:ajax uses 'update' to render content, where f:ajax uses render="id" etc..
<h:form>
<h:panelGrid columns="1">
<h:panelGroup layout="block" id="nameSection" >
<p:outputLabel for="uname" value="Name"/>
<p:inputText id="uname" value="#{onBlur.name}" required="true" requiredMessage="Enter your name">
<p:ajax event="blur" update="nameSection"/>
</p:inputText>
<h:outputText value=""/>
<p:message id="name" for="uname" />
</h:panelGroup>
<h:panelGroup layout="block" id="addressSection" >
<p:outputLabel for="add" value="Address"/>
<p:inputText id="add" value="#{onBlur.address}" required="true" requiredMessage="Enter your address">
<p:ajax event="blur" update="addressSection"/>
</p:inputText>
<h:outputText value=""/>
<p:message id="address" for="add" />
</h:panelGroup>
</h:panelGrid>
<h:commandButton value="Submit"/>
</h:form>

Get input value from parametrized method

I'm trying to fill my input with a value from a parametrized method as I can't access to this value directly with a getter.
<c:forEach items="#{operationBean.tableFields}" var="tableField" varStatus="status">
<rich:column>
<f:facet name="header">
<h:panelGroup>
<h:outputText value="#{operationBean.findLabel(tableField)}"/>
<h:inputText value="#{operationBean.filters[tableField]}" layout="block">
<a4j:ajax event="keyup" render="table" execute="#table"/>
</h:inputText>
</h:panelGroup>
</f:facet>
<c:choose>
<c:when test="#{operationBean.editableColumn(tableField)}">
<rich:inplaceInput value="#{operationBean.findOperationFieldValue(operation, tableField)}"
valueChangeListener="#{operationBean.changeOperationFieldValue}"
saveOnBlur="false">
<f:attribute name="tableField" value="#{tableField}"/>
<f:attribute name="operation" value="#{operation}"/>
<a4j:ajax execute="#this"/>
</rich:inplaceInput>
</c:when>
<c:otherwise>
<h:outputText value="#{operationBean.findOperationFieldValue(operation, tableField)}"/>
</c:otherwise>
</c:choose>
</rich:column>
</c:forEach>
Obviously, JSF tries to call a setter for the rich:inplaceInput, cannot find it, and throws
javax.el.PropertyNotWritableException: /faces/operations/table.xhtml #29,56 value="#{operationBean.findOperationFieldValue(operation, tableField)}": Illegal Syntax for Set Operation
I don't need this attempted call to a setter, as the valueChangeListenerdoes what I need.
I could create my own component and override UIInput.updateModel() but that would be a pain.

Resources