Using Omnifaces validateAllOrNone component into ui:repeat - primefaces

I have the following problem:
I try to use o:validateAllOrNone component into ui:repeat and it's work nice. But it doesn't work with my composite component.
My composite component it's really the simple p:inputText for comfortable input phone number. There I have used javascript which provides work with different phone numbers (inputPhoneNumber).
<p:inputText id="#{cc.attrs.id}" type="tel" label="Номер телефона" value="#{cc.attrs.value}" required="#{cc.attrs.required}"
styleClass="#{cc.attrs.styleClass} m-pad-left50" style="#{cc.attrs.style}">
</p:inputText>
<script>
$("#{cc.fullId}").intlTelInput(
{
utilsScript: "intl-tel-input/js/utils.js",
autoHideDialCode: false,
nationalMode: false,
preferredCountries: [#{cc.preferredCountries}],
onlyCountries: [#{cc.countries}],
dropdownContainer: 'body'
}
);
</script>
Also I have the form to create contacts such as phone number, email, skype and et. The form allows to create list of contacts. And there I have used my composite component if category of contact is phone number else simple input text:
<ui:repeat value="#{bean.contacts}" var="contact">
<p:selectOneMenu id="contact_type" value="#{contact.type}">
...
</p:selectOneMenu>
<p:outputPanel rendered="#{contact.category.equals(category.PHONE)}">
<mycomponent:inputPhoneNumber id="contact_phone_value" value="#{contact.value}" preferred="ru">
<o:validateAllOrNone components="contact_type contact_phone_value"/>
</p:outputPanel>
<p:outputPanel rendered="#{ne contact.category.equals(category.PHONE)}">
<p:inputText id="contact_other_value" value="#{contact.value}"/>
<o:validateAllOrNone components="contact_type contact_other_value"/>
</p:outputPanel>
</ui:repeat>
I have used o:validateAllOrNone to check that contact type and his value not empty. It works for p:inputText but when I have tried to used this component for mycomponent:inputPhoneNumber I have caught the following exception:
Exception message: ValidateAllOrNone attribute 'components' must refer
existing client IDs. Client ID 'contact_type' cannot be found.
I have found the question the question where I have known how to get full into ui:repeat. After that I have rewritten my code:
<ui:repeat id="contact_list" value="#{bean.contacts}" var="contact" varStatus="status">
<p:selectOneMenu id="contact_type" value="#{contact.type}">
...
</p:selectOneMenu>
<p:outputPanel rendered="#{contact.category.equals(category.PHONE)}">
<mycomponent:inputPhoneNumber id="contact_phone_value" value="#{contact.value}" preferred="ru">
<o:validateAllOrNone components="contact_creation_form-contact_list-#{status.index}-contact_type contact_phone_value"/>
</p:outputPanel>
<p:outputPanel rendered="#{ne contact.category.equals(category.PHONE)}">
<p:inputText id="contact_other_value" value="#{contact.value}"/>
<o:validateAllOrNone components="contact_type contact_other_value"/>
</p:outputPanel>
</ui:repeat>
Now I have put the correct id for contact type, but I caught the same exception:
Exception message: ValidateAllOrNone attribute 'components' must refer
existing client IDs. Client ID
'contact_creation_form-list-2-contact_type' cannot be found.
How can I fix this proglem?

I should went from other side. It's easy to get the full id for the composite component and use it at o:validateAllOrNone. It fixed the problem. The correct id for composite component in this case it is contact_phone_value-contact_phone_value. After that code lookes like:
<ui:repeat value="#{bean.contacts}" var="contact">
<p:selectOneMenu id="contact_type" value="#{contact.type}">
...
</p:selectOneMenu>
<p:outputPanel rendered="#{contact.category.equals(category.PHONE)}">
<mycomponent:inputPhoneNumber id="contact_phone_value" value="#{contact.value}" preferred="ru">
<o:validateAllOrNone components="contact_type contact_phone_value-contact_phone_value"/>
</p:outputPanel>
<p:outputPanel rendered="#{ne contact.category.equals(category.PHONE)}">
<p:inputText id="contact_other_value" value="#{contact.value}"/>
<o:validateAllOrNone components="contact_type contact_other_value"/>
</p:outputPanel>
</ui:repeat>
Also you should know that I use '-' instead ':' for id delimeter.

Related

<p:autoComplete> inside cell editable <p:dataTable> not invoking complete method

I have a dataTable which has cell editing and global filter capability:
<p:dataTable id="tbl01" value="#{userMappingBacking.staffList}" editable="true" editMode="cell" filteredValue="#{userMappingBacking.staffListFiltered}" var="s" rowKey="#{s.id}" widgetVar="tbl101WV">
...
<f:facet name="header">
<p:outputPanel>
<p:toolbar>
<p:toolbarGroup align="${text.line_start}">
<p:commandButton value="#{text.save}" action="#{userMappingBacking.saveChanges}" update="msgs"/>
</p:toolbarGroup>
<p:toolbarGroup align="${text.line_end}">
<h:outputText value="#{text.search_all_fields}:"/>
<p:spacer width="10"/>
<h:inputText id="globalFilter" onkeyup="PF('tbl101WV').filter()" />
</p:toolbarGroup>
</p:toolbar>
</p:outputPanel>
</f:facet>
...
<p:column headerText="#{text.user}" filterBy="#{s.userName}" filterable="false">
<p:cellEditor id="ceUser">
<f:facet name="output"><h:outputText value="#{s.userName}"/></f:facet>
<f:facet name="input">
<p:autoComplete id="acUser" dropdown="true" value="#{s.userName}" completeMethod="#{userMappingBacking.completeUnAssignedUser}"/>
</f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
and the backing bean userMappingBacking supports all the methods and works fine.
My problem is quite strange, the <p:autoComplete id="acUser"... doesn't invoke the complete method unless a filter is applied to the table, after a filter application every thing works fine, but before that no values are completed in the p:autoComplete.
Could any one help or give an insight into this.
I actually found the problem to be in the backing bean, I had 3 lists:
staffList = new ArrayList<>();
staffListFiltered = new ArrayList<>();
userDTOList = new ArrayList<>();
that I fill in a viewAction listener
public void loadStaffListAction() {
staffList = zaties.listAllStaff();
staffListFiltered = zaties.listAllStaff();
userDTOList = iacw.listAllUsers();
}
the problem was having 2 different lists staffList and staffListFiltered filled with different objects from the service, so changing the code like this:
public void loadStaffListAction() {
staffList = zaties.listAllStaff();
staffListFiltered = staffList;
userDTOList = iacw.listAllUsers();
}
and this solved the problem, nevertheless this is not the best practice, as explained below.
Common Error:
in the primefaces showcase for filtered datatable the never initialize the filteredValue list to any thing, they leave it as null so the datatable filter logic initialize it in the right way, paying attention to this detail I advise:
Don't initialize any thing unless you get an error.
comments are welcome!

How to use the same datatable for all the tabs primefaces (resize not working in this case)

I am using primefaces 5.3 and jsf 2.2.6.
I have created two static tabs to see if it works to use the same xhtml page (transactionsPage) that contains a datatable.
These are the tabs:
<h:form id="formTabs">
<p:tabView id="tabs" activeIndex="#{mainPage.index}">
<p:ajax event="tabClose" listener="#{mainPage.remove}" update="formTabs" />
<p:ajax event="tabChange" listener="#{mainPage.changeTab}" update="formTabs" />
<p:tab id="transAssembling" title="ASSEMBLING" closable="true">
<f:subview id="tab0">
<ui:include src="transactionsPage.xhtml">
<ui:param name="status" value="ASSEMBLING" />
<ui:param name="columnList" value="#{tabs.list[0].columnList}" />
</ui:include>
</f:subview>
</p:tab>
<p:tab id="transPrinting" title="PRINTING" closable="true">
<f:subview id="tab1">
<ui:include src="transactionsPage.xhtml">
<ui:param name="status" value="PRINTING" />
<ui:param name="columnList" value="#{tabs.list[1].columnList}" />
</ui:include>
</f:subview>
</p:tab>
</p:tabView>
</h:form>
I used the subView, in order to have different ids for the datatable from the included transactionsPage.xhtml, so that I can use the same xhtml page for all tabs and only change the columns and data, that are calculated in the managed bean of the transactionsPage.xhtml.
So for the datatable
from the first tab: the absolute path would be
formTabs:tabs:tab0:transactionsTable
from the second tab: the absolute path would be
formTabs:tabs:tab1:transactionsTable
This is the datatable from the transactionsPage:
<p:dataTable id="transactionsTable" var="data" value="#{transactionsPage.ttList}" widgetVar="projectData"
rowKey="#{data.id}"
draggableColumns="true"
draggableRows="true"
resizableColumns="true" emptyMessage="#{msg['form.noTransactionsFound']}" rows="20"
selectionMode="single" selection="#{transactionsPage.selectedTransaction}"
filteredValue="#{transactionsPage.fitleredttList}" paginator="true" paginatorPosition="both" paginatorTemplate="{CurrentPageReport} {RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}"
>
<p:ajax event="colResize" listener="#{transactionsPage.onColumnResize}" update="transactionsTable"/>
<f:ajax event="rowSelect" render="formTabs"/>
<!-- Stiky does not work with column filtering paginator="true" paginatorPosition="bottom" paginatorTemplate="{CurrentPageReport} {RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} " stickyHeader="true" -->
<f:facet name="header">
<p:outputPanel styleClass="mainPageProjectsTableHeader" >
<h:outputText value="#{msg['form.searchAllFields']}" style="float:left; margin-right:10px;"/>
<p:inputText id="globalFilter" onkeyup="PF('projectData').filter()" style="width:150px; float:left" placeholder=" #{msg['form.enterKeyword']}"/>
<p:commandButton id="toggler" type="button" value="#{msg['form.columns']}"
styleClass="columnSelector" icon="ui-icon-calculator" />
<p:columnToggler datasource="transactionsTable" trigger="toggler" >
<p:ajax event="toggle" listener="#{transactionsPage.onToggle}" />
</p:columnToggler>
</p:outputPanel>
</f:facet>
<c:forEach var="column" items="#{transactionsPage.columnList}">
<p:column id="#{column.id}" filterStyleClass="#{column.filterStyleClass}" headerText="#{column.title}" visible="#{column.visible}" width="#{column.width}" filterBy="#{data[column.property]}" filterMatchMode="contains" styleClass="mainPageCompanyColumn">
<f:attribute name="rtcCol" value="#{column}"/>
<h:outputText value="#{data[column.property]}" />
</p:column>
</c:forEach>
</p:dataTable>
The problem is the following:
When I want to resize a column in the last opened tab, it works and I see that before calling the resize method from the managed bean, a queueEvent method from the primefaces Datatable.class is called(in this method it takes the decision which event to call), in which the clientId is correct formTabs:tabs:tab1:transactionsTable and then the resize method is being called.
But when I go in another tab, the clientId from the queueEvent method remains the same, from the last tab openend formTabs:tabs:tab1:transactionsTable and I get the following exception, so that the resize method is not be called anymore.
java.lang.NullPointerException
at org.primefaces.component.datatable.DataTable.findColumnInGroup(DataTable.java:909)
at org.primefaces.component.datatable.DataTable.findColumn(DataTable.java:900)
at org.primefaces.component.datatable.DataTable.queueEvent(DataTable.java:814)
at org.primefaces.behavior.ajax.AjaxBehaviorRenderer.decode(AjaxBehaviorRenderer.java:47)
at javax.faces.component.behavior.ClientBehaviorBase.decode(ClientBehaviorBase.java:132)
at org.primefaces.renderkit.CoreRenderer.decodeBehaviors(CoreRenderer.java:530)
at org.primefaces.component.datatable.DataTableRenderer.decode(DataTableRenderer.java:66)
I assume this happens, because of the clientId of the datatable, which is not updated to the datatable from the tab, where I have changed the focus on.
So the question would be: How could I change the whole path/id to the newly opened tab/datatable:
formTabs:tabs:tab0:transactionsTable
because my assumption is that that's why the resize method is not being called for another tab then the last opened tab.
If it's not clear enough or the architecture is bad, then the question would be
How to use the same xhtml page/datatable for 11 tabs without creating 11 static datatables?
So, it seemed that the problem was the widgetVar from the datatable, because it was used the same value for the widgetVar for every single datatable and that's why it had the same clientId, because the same clientId was added to the DOM.
If you want to read about the widgetVar:
http://blog.hatemalimam.com/intro-to-primefaces-widgetvar/
So, as a conclusion, I have set dynamically a value to the widgetVar for each tab and the clientId in the primefaces Datatable class was correct,the resize method was called and it worked.

Why are the columns of my primefaces dataTable are not rendered?

following p:dataTable with dynamic columns:
<p:dataTable value="#{searchMaskBL.getSearchMaskDescription().getRows()}" var="curRow">
<p:columns value="#{curRow.getColumns()}" var="curColumn">
<h:outputLabel value="#{curColumn.label} #{curColumn.colonOnRightSide ? ':' : ''}" for="colInputTextId" />
<h:inputText id="colInputTextId" value="" />
</p:columns>
</p:dataTable>
The iteration over the rows defined with #{searchMaskBL.getSearchMaskDescription().getRows()} works, but #{curRow.getColumns()} is never called. Also curRow.columns does not work. What' wrong? The ui model has rows and columns.
Regards
Oliver
You can't have the columns value attribute iterate over the current row...
According to the columns example in the PF showcase, you should it like this (but adapt it to your scenario:
<p:dataTable id="cars" var="car" value="#{dtColumnsView.cars}" widgetVar="carsTable" filteredValue="#{dtColumnsView.filteredCars}">
<p:columns value="#{dtColumnsView.columns}" var="column" columnIndexVar="colIndex" sortBy="#{car[column.property]}" filterBy="#{car[column.property]}">
<f:facet name="header">
<h:outputText value="#{column.header}" />
</f:facet>
<h:outputText value="#{car[column.property]}" />
</p:columns>
</p:dataTable>
Where you populate a columns model and iterate over that in the value attribute of the colums tag

primefaces rowEdit closes after validationFailed()

I am using Primefaces 4.0 and JSF 2.2. When I make a DataTable with row Edit and I set a valdiationFailed() on the rowEdit event, the roweditor is closing, which I want to prevent.
I added an oncomplete js function like:
<p:ajax event="rowEdit" listener="#{customerUI.onInvoiceRowEdit}"
oncomplete="if(!args.validationFailed) {updateTable();}" update=":messages" />
My remote command is as follows:
<p:remoteCommand name="updateTable" update=":form:addressTabs:customerTable" />
So this keeps the editor when the validation fails, but now the editors accept and cancel buttons doesn't work, so does editing other things on the side until i do a manual refresh.
I just want the editor to stay when the validation fails and to correct the input, if the validation went good, the editor can be closed.
Anyone any solution to this?
So I had a tangentially related problem and this question helped me figure out a solution so I thought I should share it here in case someone else lands on this question with a similar issue and needs help.
So I had a dataTable and a rowEdit ajax call to a function when a cell within the row is edited, I also used a remoteCommand to update the dataTable after I make some changes in the DB. Problem was if the validation for the cell edit value failed the remoteCommand would refresh the form and the error messages would disappear before they could be read. I wanted the ajax call on rowEdit to only go through if there were no validation errors, otherwise I wanted to display the error message with the row editor still open. So I used the args.validationFailed parameter as shown in the question to prevent the remoteCommand from being executed in case the custom validator fails. The following is a basic example of what I did.
JSF page:-
<h:form id="form_name">
<p:remoteCommand name="refreshForm" update="#form" />
<p:dataTable id="table_id" var="varTableData"
value="#{bean.tablerows}"
editable="true">
<p:ajax event="rowEdit"
listener="#{bean.onRowEdit}"
oncomplete="if(!args.validationFailed) refreshForm()" />
<p:column>
<f:facet name="header">
<h:outputText value="Column Title" />
</f:facet>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{varTableData.someValue}" />
</f:facet>
<f:facet name="input">
<p:inputText id="cellId"
value="#{varTableData.someValue}"
label="Some Label" required="true" style="width:100%"
validator="#{bean.validationMethod}">
</p:inputText>
<p:message id="someMsg" for="cellId" />
</f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
</h:form>
Custom Validation Method :-
public void validationMethod(FacesContext context, UIComponent comp, Object value) {
int someCellValue = (int) value;
if (someCellValue < 6) {
((UIInput) comp).setValid(false);
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
"Some error message",
"some error message");
context.addMessage(comp.getClientId(context), message);
}
}

primefaces rowediting datatable ejb update returns old data

Salut :), iam a newbie in primefaces and ajax
Iam using primefaces 3.4, glassfish 3.1, jsf2.0 and ejb 3. I tried to implement primefaces showcase datatable rowediting. But when i validate the updated value into the datatable, i get the old value. This is my code :
<h:form id="form">
<p:growl id="messages" showDetail="true"/>
<p:dataTable var="item" value="#{jSFMBean.allContacts}" id="contactList" editable="true">
<p:ajax event="rowEdit" listener="#{jSFMBean.onEdit}" update="#this :form:messages" />
<p:ajax event="rowEditCancel" listener="#{jSFMBean.onCancel}" update=":form:messages" />
<p:column headerText="EMAIL" style="width:125px">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{item.email}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{item.email}" label="EMAIL"/>
</f:facet>
</p:cellEditor>
</p:column><p:column headerText="Options" style="width:50px">
<p:rowEditor />
</p:column>
</p:dataTable>
<h:outputText value="#{jSFMBean.selectedContact.displayname}" />
the methods are :
public void onEdit(RowEditEvent event) {
this.session.updateContact((Contacts) event.getObject());
FacesMessage msg = new FacesMessage("Edition contact: ", ((Contacts) event.getObject()).getDisplayname());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
(Contacts) event.getObject() always get the old value :(. It's like the getter of the datatable fireup first before ajax update to the database.
what iam i doing wrong ? thank you for your help solving this .
Currently you're editing values within the object. It looks like you still need to make a call back to your database to update the value there.
It seems that whenever you need your dataTable you are getting it from your database and that's why event.getObject() always returns the old value.So in the getter of your datatable you need to add:
if (allContacts== null){
allContacts= (List<Contacts>) yourservice.getAll(); /*this refers to the function that get the list from the database*/
}
return allContacts;
I hope that may help you.
Most probably the problem is with your backing bean. if you have used #Named annotation instead of #ManagedBean (javax.faces.bean.ManagedBean) for your backing bean, you faces this kind of problems. Simply replace
#Named (value="YourBeanName")
with
#ManagedBean (name="YourBeanName")