I basically have two input field I display if the value is currently empty or null. if it is not, I display an outputText. Those two values are currency values stored in a Long object and I use a converter to display the data properly (I can't use PrimeFaces' inputNumber since I am using PrimeFaces 5.3). My problem is the following :
<c:set var="edtVal1" value="#{bean.val1 ne null and bean.val1 ne 0}" scope="request" />
<c:set var="edtVal2" value="#{bean.val2 ne null and bean.val2 ne 0}" scope="request" />
<p:panelGrid>
<p:row>
<p:column colspan="2">
<p:messages id="mainMessages" globalOnly="false" autoUpdate="true" showDetail="true" />
</p:column>
</p:row>
<!-- [...] -->
<p:row>
<p:column styleClass="col-quarter col-label2">
<h:outputText value="value 1" />
</p:column>
<p:column styleClass="col-quarter col-value2" rendered="#{edtVal1}">
<h:outputText id="val1Output" value="#{bean.val1}" converter="myConverter" />
</p:column>
<p:column styleClass="col-quarter" rendered="#{not edtVal1}">
<p:inputText id="val1Input" value="#{bean.val1}" converter="myConverter">
<p:ajax update="mainMessages val1Input" event="change" />
</p:inputText>
</p:column>
</p:row>
<p:row>
<p:column styleClass="col-quarter col-label2">
<h:outputText value="value 2" />
</p:column>
<p:column styleClass="col-quarter col-value2" rendered="#{edtVal2}">
<h:outputText id="val1Output" value="#{bean.val2}" converter="myConverter" />
</p:column>
<p:column styleClass="col-quarter" rendered="#{not edtVal2}">
<p:inputText id="val1Input" value="#{bean.val2}" converter="myConverter">
<p:ajax update="mainMessages val1Input" event="change" />
</p:inputText>
</p:column>
</p:row>
</p:panelGrid>
when I put it like this, the messages thrown by the converter are displayed, but none of the fields are updated. However, if I use the same boolean variable for both input/output options (changed the variable used in rendered attribute of the 1rst data row to use edtVal2 in both) like so :
<p:row>
<p:column styleClass="col-quarter col-label2">
<h:outputText value="value 1" />
</p:column>
<p:column styleClass="col-quarter col-value2" rendered="#{edtVal1}">
<h:outputText id="val1Output" value="#{bean.val1}" converter="myConverter" />
</p:column>
<p:column styleClass="col-quarter" rendered="#{not edtVal1}">
<p:inputText id="val1Input" value="#{bean.val1}" converter="myConverter">
<p:ajax update="mainMessages val1Input" event="change" />
</p:inputText>
</p:column>
</p:row>
The first field updates successfully and the second once still does not work.
Using a converter to display a formated data is a workaround I already done and it works just as expected and I use the same converter than before. But this time, I don't understand why it's not working.
The converter is important to reproduce the issue, but any custom converter seems to do the job.
Any other solutions are still welcome on this post, but I managed to find a working solution :
when I changed the rendered attribute to a constant string, the issue was absent. So I think the problem comes from a misunderstanding of <c:set>.
My solution was to use a the bean as a controller. I changed the variables from the xhtml file to properties in the controller and now everything works fine. So I removed all <c:set> from my xhtml and use a proper MVC pattern on that page now.
Note :
For those who don't know what MVC is : it's a neat architectural pattern that divides clearly the user interface and manipulated data. Learn more on wikipedia.
Related
I am trying to enable/disable a commandLink depending more than one condition.
At the beginning the commandLink is disabled. To enable it, I must click on a commandButton that activates a boolean flag (this point is currently working) and two inputText must be filled.
CommandLink:
<p:commandLink id="buttonGuardar" action="#{vinculacionesGestionDetalleController.buttonGuardar}" update="#form" process="#form" styleClass="fa-commandlink fa-floppy-o" immediate="true" disabled="#{vinculacionesGestionDetalleController.flagGuardar and empty vinculacionesGestionDetalleController.vinculacionLaboral.denominacionCas and empty vinculacionesGestionDetalleController.vinculacionLaboral.denominacionVal}">
<h:outputText value="#{msg.guardar}" />
</p:commandLink>
commandButton that returns a boolean flag from the controller:
<p:commandButton id="validacionesValidarCodigoButton" actionListener="#{vinculacionesGestionDetalleController.buttonValidar}" value="Validar" styleClass="searchButton" icon="fa fa-button fa-check-circle" process="#form" style="margin-left: 20px;" update="buttonGuardar">
</p:commandButton>
inputText:
<p:row>
<p:column styleClass="alignTextRight">
<h:outputLabel value="#{msg.vinculaciones_gestion_detalle_denominacionCas}" for="inputDenominacionCas" />
</p:column>
<p:column>
<p:inputText id="inputDenominacionCas" style="width:100%" value="#{vinculacionesGestionDetalleController.vinculacionLaboral.denominacionCas}" />
</p:column>
</p:row>
<p:row>
<p:column styleClass="alignTextRight">
<h:outputLabel value="#{msg.vinculaciones_gestion_detalle_denominacionVal}" for="inputDenominacionVal" />
</p:column>
<p:column>
<p:inputText id="inputDenominacionVal" style="width:100%" value="#{vinculacionesGestionDetalleController.vinculacionLaboral.denominacionVal}" />
</p:column>
</p:row>
As you can see, I have tried using more than two conditions on disable property of commandLink:
disabled="#{vinculacionesGestionDetalleController.flagGuardar and not empty vinculacionesGestionDetalleController.vinculacionLaboral.denominacionCas and not empty vinculacionesGestionDetalleController.vinculacionLaboral.denominacionVal}"
But it is not working.
Firstly, logical operations that in "disabled" attribute are wrong. As I understood, you want to enable the link when flag is true and inputTexts are not empty.
enabled="#{flag and not empty inputText1 and not empty inputText2}"
Oh no, commandLink doesn't have enabled attribute. No problem:
disabled="#{not (flag and not empty inputText1 and not empty inputText2)}"
Now the changes at the values of inputTexts must trigger an ajax event that will update the commandLink.
<p:row>
<p:column styleClass="alignTextRight">
<h:outputLabel value="#{msg.vinculaciones_gestion_detalle_denominacionCas}" for="inputDenominacionCas" />
</p:column>
<p:column>
<p:inputText id="inputDenominacionCas" style="width:100%" value="#{vinculacionesGestionDetalleController.vinculacionLaboral.denominacionCas}" >
<p:ajax event="keyup" update="buttonGuardar"/>
</p:inputText>
</p:column>
</p:row>
<p:row>
<p:column styleClass="alignTextRight">
<h:outputLabel value="#{msg.vinculaciones_gestion_detalle_denominacionVal}" for="inputDenominacionVal" />
</p:column>
<p:column>
<p:inputText id="inputDenominacionVal" style="width:100%" value="#{vinculacionesGestionDetalleController.vinculacionLaboral.denominacionVal}" >
<p:ajax event="keyup" update="buttonGuardar"/>
</p:inputText>
</p:column>
</p:row>
If you want ajax event get triggered only when inputText lose focus, you can use "blur" event instead of "keyup".
I have a PrimeFaces p:dataTable with one column of type p:cellEditor with an p:inputText field.
This inputText is supposed to be required but if I set required="true" and leave the input empty nothing happens / no message is shown. The form including the above is submitted anyway.
Here's my code, especially the <p:column headerText="Data Value"> part:
<h:form id="my-form">
<p:dataTable var="dataItem" rowIndexVar="rowIndex" value="#{backingBean.dataList}" draggableRows="true" editable="true" editMode="cell">
<p:ajax event="rowReorder" update="#form"/>
<p:column headerText="Order Position">
<h:outputText value="#{rowIndex+1}" />
</p:column>
<p:column headerText="Data Name">
<h:outputText value="#{dataItem.name}" />
</p:column>
<p:column headerText="Data Value">
<p:cellEditor>
<f:facet name="output"><h:outputText value="#{dataItem.value}" /></f:facet>
<f:facet name="input"><p:inputText required="true" requiredMessage="Please insert a value" id="valueInput" value="#{dataItem.value}" style="width:100%"/></f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
<div>
<h:commandLink action="#{backingBean.submit()}">Submit</h:commandLink>
</div>
<h:messages id="validateMsg" />
</h:form>
The submitting h:commandLink is not an ajax call. But in my opinion it shouldn't submit the form anyway as long as the required p:inputText fields are empty.
I also tried using h:inputText instead of p:inputText with the same result.
I tried to add a required h:inputText outside the p:dataTable which works as expected and prevents the form from being submitted as long as it is empty.
Any ideas about how I get a required p:inputText field in p:cellEdit ?
According to rion18's suggestion. I'm checking in my backing bean if all values are set. Only if all values are set the submit button is shown. Here's how I ended up doing this:
<h:form id="my-form">
<p:dataTable var="dataItem" rowIndexVar="rowIndex" value="#{backingBean.dataList}" draggableRows="true" editable="true" editMode="cell">
<p:ajax event="cellEdit" update=":#{p:component('submit-button-group')}" />
<p:column>
...
</p:column>
</p:dataTable>
<div>
<h:panelGroup id="submit-button-group">
<h:commandLink action="#{backingBean.submit()}" rendered="#{backingBean.isAllValuesSet()}">Submit</h:commandLink>
</h:panelGroup>
</div>
</h:form>
In my backing bean I have a simple function that iterates over the dataList:
public boolean isAllValuesSet(){
for(DataItem item:dataItems){
if(item.getValue()==null || item.getValue().isEmpty()){
return false;
}
}
return true;
}
I am creating a form using facelets. One input field looks like this:
<p:inputText id="initials" value="#{dilution.initials}" />
dilution is a entity bean and the initials field has two validation constraints set on it. One size constraint and one regex pattern constraint. My problem is getting error messages for both constraints to display next to the input field. Using the <h:message> only display one of the messages and using <h:messages> displays all input fields error messages or nothing (when I tried setting <h:messages for="initials" autoUpdate="true" />).
Is there any simple way to do this?
The full form:
<h:form id="addDilForm">
<p:panel>
<p:messages autoUpdate="true" showDetail="TRUE" />
<p:panelGrid>
<f:facet name="header" >
<p:row><p:column colspan="3">Ny spädningsfaktor</p:column></p:row>
</f:facet>
<p:row>
<p:column colspan="1">
<p:outputLabel for="sampT">Provtyp</p:outputLabel>
</p:column>
<p:column>
<p:selectOneMenu id="sampT" required="true" value="#{dilution.dilution.sampleType.ID}" >
<f:selectItem itemLabel="-" itemValue="" />
<f:selectItems value="#{SampleTypeController.samples}" var="samp" itemLabel="#{samp.name}" itemValue="#{samp.ID}" />
</p:selectOneMenu>
</p:column>
<p:column>
<p:message for="sampT" />
</p:column>
</p:row>
<p:row>
<p:column>
<p:outputLabel for="initials">Initialer</p:outputLabel>
</p:column>
<p:column >
<p:inputText id="initials" value="#{dilution.initials}" />
</p:column>
<p:column>
<p:message for="initials" />
</p:column>
</p:row>
<f:facet name="footer">
<p:row>
<p:column colspan="3">
<p:commandButton value="Save" action="#{dilution.save()}" update="addDilForm" icon="ui-icon-check" />
</p:column>
</p:row>
</f:facet>
</p:panelGrid>
</p:panel>
</h:form>
Using the <h:message> only display one of the messages
Just use <h:messages> with the plural "s" instead of <h:message> while keeping the for attribute.
<h:messages for="initials" />
The <p:messages> works the same way, only with a different UI.
What is the filter match mode for global filter (not the individual column filter which defaults to 'startsWith') and how to change it?
The reason I ask is, when I use the global filter with match mode set to 'startsWith' in all my columns, still I get values with 'contains' filter mode. See screenshot below.
I shouldn't be getting the rows other than the first row as I specified 'startsWith' in all columns.
Here is my datatable,
<h:form id="countryTable">
<p:dataTable rowKey="" value="#{countryBean.countriesList}"
var="country" selection="#{countryBean.selectedCountries}"
styleClass="data-table-style" widgetVar="countryTableWVar"
filteredValue="#{countryBean.filteredCountries}">
<f:facet name="header">
<div class="align-left">
<p:outputPanel>
<h:outputText value="Search all fields:" />
<p:inputText id="globalFilter" onkeyup="countryTableWVar.filter();"
style="width:150px" />
</p:outputPanel>
</div>
</f:facet>
<p:column selectionMode="multiple" style="width:2%;" />
<p:column headerText="Numeric Code" filterMatchMode="startsWith"
filterStyle="display:none" filterBy="numericCode">
<h:outputText value="#{country.numericCode}"></h:outputText>
</p:column>
<p:column headerText="Alpha_2 Code" filterMatchMode="startsWith"
filterStyle="display:none" filterBy="alpha2">
<h:outputText value="#{country.alpha2}"></h:outputText>
</p:column>
<p:column headerText="Alpha_3 Code" filterMatchMode="startsWith"
filterStyle="display:none" filterBy="alpha3">
<h:outputText value="#{country.alpha3}"></h:outputText>
</p:column>
<p:column headerText="Name" filterMatchMode="startsWith"
filterStyle="display:none" filterBy="name">
<h:outputText value="#{country.name}"></h:outputText>
</p:column>
</p:dataTable>
</h:form>
How to change the datatable global filter match mode?
If you look at the source code of primefaces
org.primefaces.component.datatable.feature.FilterFeature.java
At line 133 you can see primefaces uses contains method of String
if(columnValue.toLowerCase(filterLocale).contains(globalFilter)){
globalMatch = true;
}
So for now there is no way other than changing code according to your needs and building your own primefaces jar.
From Primefaces 4.0 docs:
Filter located at header is a global one applying on all fields, this is implemented by calling client
side API method called filter(), important part is to specify the id of the input text as globalFilter
which is a reserved identifier for datatable.
The use case would be:
<p:dataTable var="car" value="#{carBean.cars}"
filteredValue="#{carBean.filteredCars}" widgetVar="carsTable">
<f:facet name="header">
<p:outputPanel>
<h:outputText value="Search all fields:" />
<h:inputText id="globalFilter" onkeyup="PF('carsTable').filter()" />
</p:outputPanel>
</f:facet>
<p:column filterBy="model" headerText="Model" filterMatchMode="contains">
<h:outputText value="#{car.model}" />
</p:column>
<p:column filterBy="year" headerText="Year" footerText="startsWith">
<h:outputText value="#{car.year}" />
</p:column>
<p:column filterBy="manufacturer" headerText="Manufacturer"
filterOptions="#{carBean.manufacturerOptions}" filterMatchMode="exact">
<h:outputText value="#{car.manufacturer}" />
</p:column>
<p:column filterBy="color" headerText="Color" filterMatchMode="endsWith">
<h:outputText value="#{car.color}" />
</p:column>
</p:dataTable>
It doesn't tell anything about startsWithor endsWith specific cases for global filter. It could be interesting to open a thread on the issue tracker.
i am currently using a pannel grid to display some data retrived from a database, this is working fine, the layout is not perfect but it displays all of the correct data, however i am wanting to use a datatable for looks more than anything, i have tried to use the outputText from the pannel grid but when i run the page it just says no data found, but on the same page the same code displays the data in the pannel grid
what am i doing wrong ?
this is the code for the working pannel grid
<!-- heading -->
<f:facet name="header">
User Details
</f:facet>
<h:outputText value="#{bundle.ViewUserdetailsLabel_id}"/>
<!-- adding in a small effect here that will fade a message when a user hovers over the id number or username -->
<h:outputLink id="id1" value="#">
<h:outputText id="id" value="#{userdetailsController.selected.id}" title="#{bundle.ViewUserdetailsTitle_id}"/>
</h:outputLink>
<p:tooltip for="id" value="This is your I.D. Number" showEffect="fade" hideEffect="fade" />
<h:outputText value="#{bundle.ViewUserdetailsLabel_username}"/>
<h:outputLink id="username1" value="#">
<h:outputText id="username" value="#{userdetailsController.selected.username}" title="#{bundle.ViewUserdetailsTitle_username}"/>
</h:outputLink>
<p:tooltip for="username" value="Your registered username, this can be changed" showEffect="fade" hideEffect="fade" />
</p:panelGrid>
and here is the not working datatable
<p:dataTable>
<p:column >
<f:facet name="header">
<h:outputText value="{bundle.ViewUserdetailsLabel_id}"/>
</f:facet>
<h:outputText value="{userdetailsController.selected.id}" />
</p:column>
<p:column headerText="username" >
<f:facet name="header">
<h:outputText value="{bundle.ListUserdetailsTitle_username}"/>
</f:facet>
<h:outputText value="{userdetailsController.selected.username}" />
</p:column>
</p:dataTable>
as you can see the outputText values are the same so it should work right ?
thanks
If you happen to have only few hardcoded values to display in a form of a table, then you are better off using <h:panelGrid>. If you however have a list of objects that you want to iterate over and display them quickly then use <p:dataTable>.
Let's say we have a List of employees
<p:dataTable var="employee" value="#{tableBean.employees}">
<p:column headerText="Name">
<h:outputText value="#{employee.name}" />
</p:column>
<p:column headerText="Age">
<h:outputText value="#{employee.age}" />
</p:column>
<p:column headerText="Sex">
<h:outputText value="#{employee.sex}" />
</p:column>
</p:dataTable>
then your table would look like this. var in this case is completely arbitrary, you could for instance call it 'fluffy' if you wanted. There are a lot of settings you can use with dataTable like pagination, export, sorting etc. But I suggest you familiarize yourself with Primefaces showcase