Datatable Global Filter - Unexpected Behavior - ajax

I have a globalfilter in a Datatable to work when the user hit Enter:
It filters as expected. But, strangely, after the datatable is filtered, a createForm, inside a p:dialog, is displayed too, which it is not expected; this createForm is, and should, be displayed only when the user clicks in the createButton that evokes it.
Above, code excerpts related to the components.
The createButton and the Datatable:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:form id="DemandasListForm">
<p:panel id="PanelListForm">
<p:commandButton id="createButton" icon="fa fa-plus-square" value="#{adeBundle.CreateDemanda}" update=":DemandasCreateForm" oncomplete="PF('DemandasCreateDialog').show()" actionListener="#{demandasController.prepareCreate}" />
<f:facet name="header">
<p:outputPanel style="text-align: right">
<p:inputText id="globalFilter" onkeypress="if (event.keyCode === 13) {PF('demandasTable').filter();}" placeholder="Type something and press ENTER." />
</p:outputPanel>
</f:facet>
<p:dataTable id="datalist"
value="#{demandasController.items}"
lazy="false"
rowKey="#{item.id}"
var="item"
paginator="true"
paginatorPosition="bottom"
selectionMode="single"
selection="#{demandasController.selected}"
filteredValue="#{demandasController.filteredDemandas}"
filterDelay="1000" <!-- doesn't work for globalfilter, only for the columns-->
widgetVar="demandasTable">
...
</p:dataTable>
The dialog:
<ui:composition>
<p:dialog id="DemandasCreateDlg" widgetVar="DemandasCreateDialog" modal="true" appendTo="#(body)" closeOnEscape="true">
<h:form id="DemandasCreateForm">
...
Does anyone knows how can I fix this ?
Thanks in advance.

Can try to return false like this..
onkeypress="if (event.keyCode === 13) {PF('demandasTable').filter(); return false;}"
That will break out after the filter method is called and not let the ENTER key propagate. What I think is happening is the ENTER key is submitting the first button on the form which is your Command Button to open the dialog. Default browser behavior is to submit the first button it finds on a form when you press ENTER.

Related

Why does JSF/AJAX skip phases?

I have page with an initial search/h:datatable on top. It renders well and displays all the text units (tokens) which are available.
Leading each row of the search results with a button "view". This button rerenders the panel group textUnitGroup, which holds the details of this token. Now, that works just fine. I can click all the token's view button and the area is refreshed WITHOUT a page reload. With the input fields of that panel group (form in embeded) I can also persist new tokens. Works, too.
However, if I load token details into that detail form (form is rendered again), and I press the "save text" button, JSF phase 2, 3, 4 and 5 are skipped (which did not happen, when I save a new token and the "view" button has NOT been clicked before).
12:31:44,174 INFO [org.exadel.helper] (default task-22) L:54 BEFORE RESTORE_VIEW 1
12:31:44,180 INFO [org.exadel.helper] (default task-22) L:67 AFTER RESTORE_VIEW 1
12:31:44,181 INFO [org.exadel.helper] (default task-22) L:54 BEFORE RENDER_RESPONSE 6
12:31:44,257 INFO [org.exadel.helper] (default task-22) L:67 AFTER RENDER_RESPONSE 6
Somewhat changes when re-rendering the details form resp. panel group. But I don't understand why. There is NO error in the log. But it is certainly the cause of the JSF phase-skipping (otherwise the insertion of a new token would not work, too).
This is the xhtml file. Let me know if you need more.
<!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:c="http://java.sun.com/jsp/jstl/core"
xmlns:mywidgets="http://java.sun.com/jsf/composite/widgets"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:pt="http://xmlns.jcp.org/jsf/passthrough">
<ui:composition template="/templates/overviewTemplate.xhtml">
<!-- <ui:composition template="/templates/contentTemplate.xhtml"> -->
<ui:define name="title">Text Administration</ui:define>
<ui:define name="body">
<h1>Text Administration</h1>
<h:panelGroup layout="block" id="searchListGroup" rendered="true">
<h:form id="listOfTextUnits">
<h:inputText autocomplete="true" style="width: 300px"
value="#{textController.searchFilter}"
pt:placeholder="Token or text in English" pt:autofocus="true"
title="Search by token or text in English">
<f:ajax event="keyup" execute="#this" render="textTable" />
</h:inputText>
<p class="betweenSections" />
<h:dataTable id="textTable"
value="#{textController.findTextUnitsByString()}" var="textUnit"
styleClass="data-table" headerClass="table-header"
rowClasses="table-odd-row,table-even-row">
<h:column>
<!-- column header -->
<f:facet name="header">Action</f:facet>
<!-- row record -->
<h:commandButton value="view" styleClass="mini"
action="#{textController.loadTextDetail()}">
<f:param name="id" value="#{textUnit.id}" />
<f:ajax execute="#form" render="textUnitGroup" />
</h:commandButton>
</h:column>
<h:column sortBy="#{textUnit.token}"
filterExpression="#{empty filterValue or fn:startsWith(textUnit.token, filterValue)}"
filterValue="#{textController.searchFilter}">
<f:facet name="header">Token</f:facet>
<h:outputText value="#{textUnit.token}" />
</h:column>
<h:column>
<!-- column header -->
<f:facet name="header">Default Text</f:facet>
<!-- row record -->
#{textUnit.defaultText}
</h:column>
</h:dataTable>
</h:form>
</h:panelGroup>
<h:panelGroup layout="block" id="textUnitGroup"
rendered="true">
<h2>Text unit</h2>
<h:form id="textUnit">
<h:inputHidden id="id" value="#{textController.id}" />
<label for="token">Token</label>
<h:inputText id="token" value="#{textController.token}"
required="true"
requiredMessage="Please insert a token string for this new translation." />
<label for="text">Default Text</label>
<h:inputTextarea id="text" value="#{textController.text}"
required="true"
requiredMessage="Please insert a default text translation."
cols="100" />
<h:commandButton value="save text"
action="#{textController.saveText()}">
<f:ajax execute="#form" render="searchListGroup" />
</h:commandButton>
</h:form>
</h:panelGroup>
<p class="betweenSections" />
</ui:define>
</ui:composition>
</html>
Thanks for any hint
--------------------------------UPDATE-------------------------------
Assuming that something with the JavaScript code has gone broken, I did put the h:panelGroup within the h:form tags. Now that works. The drawback with this is, that the h2 tags is never rerendered erspectively shown. This is what I wanted in the next step. Hide the form and then display, when needed.
To properly rephrase the question: How could one re-render a panelgroup which contains multiple h:form whitout listing all the forms in the render attribute of the f:ajax tag? Not possible at all?
Thanks for any hint!

JSF PrimeFaces rowSelect for one datatable being called from another datatable

I have a Purchase datatable in a tab that lists all purchases. When you select a row, it is supposed to open a dialog that shows a list of the purchases for a particular customer. Also in the code there is a dialog for adding a new purchase in which a Customer can be selected from a list of previous customers in a datatable.
My problem is that when I select a row in the purchase table it is calling the rowSelect ajax event in the customer datatable (from inside the "New Purchase" dialog) instead of triggering it's own rowSelect event that opens the Purchase dialog.
<!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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:o="http://omnifaces.org/ui"
xmlns:of="http://omnifaces.org/functions">
<h:head>
</h:head>
<h:body>
<p:growl id="messages" showDetail="true" />
<h:form id="newPurchaseCommandForm" enctype="multipart/form-data">
<p:commandButton value="New Purchase" process="#this"
onclick="PF('newPurchase').show()" id="btnNewPurchase">
<f:actionListener binding="#{purchasesDAO.init()}" />
</p:commandButton>
</h:form>
<p:tabView id="tabView" dynamic="true" cache="true" scrollable="true"
style="font-size:12px;">
<p:tab id="tba1" title="Purchase List">
<h:form id="purchaseTableForm" enctype="multipart/form-data">
<p:dataTable id="PurchaseTable" var="purchaseVar"
rowKey="#{purchaseVar.id}"
selection="#{purchasesDAO.selectedPurchaseRow}"
widgetVar="purchasesTableSearch"
filteredValue="#{purchasesDAO.filteredPurchaseRow}"
selectionMode="single" value="#{purchasesDAO.purchaseList}"
style="font-size:10px;">
<!-- Opens dialog -->
<p:ajax event="rowSelect" listener="#{purchasesDAO.onRowSelect}"
update=":messages" oncomplete="PF('showPurchase').show()" />
...
</p:dataTable>
</h:form>
</p:tab>
</p:tabView>
<p:dialog header="Purchase Details" widgetVar="showPurchase"
id="dialog" resizable="true" modal="false" hideEffect="explode"
height="500" width="990">
...
</p:dialog>
<p:dialog header="Add New Purchase" widgetVar="newPurchase"
id="dialogNewPurchase" resizable="true" modal="true" hideEffect="explode"
closeOnEscape="true" height="600" width="900">
<h:form id="form-newcasedialog" enctype="multipart/form-data">
<p:dataTable id="CustomerTable" var="customer"
rowKey="#{customer.id}"
selection="#{purchasesDAO.selectedCustomerRow}"
widgetVar="purchasesTableSearch"
filteredValue="#{purchasesDAO.filteredCustomerRow}"
selectionMode="single" value="#{purchasesDAO.customerList}"
style="font-size:10px;">
<!-- Opens dialog -->
<p:ajax event="rowSelect" listener="#{purchasesDAO.onRowSelect3}"
process="#this" />
...
</p:dataTable>
</h:form>
</p:dialog>
</h:body>
</html>
The solution for this took me ages to find but it turned out to be a simple one-line typo.
The widgetVar for both the Customer table and the Purchases table were the same:
<p:dataTable id="CustomerTable" var="customer"
rowKey="#{customer.id}"
selection="#{purchasesDAO.selectedCustomerRow}"
widgetVar="purchasesTableSearch"
filteredValue="#{purchasesDAO.filteredCustomerRow}"
selectionMode="single" value="#{purchasesDAO.customerList}"
style="font-size:10px;">
Should be:
<p:dataTable id="CustomerTable" var="customer"
rowKey="#{customer.id}"
selection="#{purchasesDAO.selectedCustomerRow}"
widgetVar="customerTableSearch"
filteredValue="#{purchasesDAO.filteredCustomerRow}"
selectionMode="single" value="#{purchasesDAO.customerList}"
style="font-size:10px;">
This was caused by copy/pasting code during development and missing the widgetVar line when updating the code. Changing the widgetVar in the customer datatable to be different to the purchase table solved the problem.

Action of command button not invoked if I use ajax

I have the following problem:
I have a button that should invoke a method, but the page should't get refreshed (I display a dialog based on bootstrap modal after clicking on the button and it vanishes otherwise). Therefore I use ajax to say that nothing should get rendered after clicking on the button.
I already used applied it before and it worked. But in the recent version of my code the method isn't invoked anymore as long as I use ajax. If I remove the ajax part the method is invoked as it should be, but the page gets refreshed and I don't want that.
My code:
<h:form>
<ui:fragment rendered="#{bean.condition1}">
<ui:include src="facelet1.xhtml" />
</ui:fragment>
<ui:fragment rendered="#{bean.condition2}">
<ui:include src="facelet2.xhtml" />
</ui:fragment>
<h:commandButton value="Save" action="bean.method">
<f:ajax execute="#form" render="#none"/>
</h:commandButton>
<h:form>
Before I had it like this and it worked:
<h:form>
<ui:include src="bean.faceletPath" />
<h:commandButton value="Save" action="bean.method">
<f:ajax execute="#form" render="#none"/>
</h:commandButton>
<h:form>
Thanks all,
/metalhamster
Edit:
facelet1.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:body>
<ui:composition>
<h:panelGrid columns="2">
<h:outputText value="Name:">
<h:inputText value="bean.name">
<h:outputText value="Value:">
<h:inputText value="bean.value">
</h:panelGrid>
</ui:composition>
</h:body>
</html>
facelet2.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:body>
<ui:composition>
<h:panelGrid columns="2">
<h:outputText value="Name:">
<h:inputText value="bean.name">
<h:outputText value="Text:">
<h:inputText value="bean.text">
</h:panelGrid>
</ui:composition>
</h:body>
</html>

Richfaces <a4j:ajax> and <rich:popupPanel> "conflict"

I've stumbled upon a strage behavior of richfaces. Some background about my view structure:
It's mainly a <rich:extendedDataTable> where a click on a row displays info about it on a <a4j:outputPanel>
Also, each row has a context menu with items like "Create", "Edit", etc... that pops a <rich:popupPanel>
The component structure is this:
<h:panelGrid columns="2">
<h:column>
<rich:dataScroller for="testTable" maxPages="7"/>
<rich:extendedDataTable id="testTable" value="#{testController.items}" rendered="#{testController.items.rowCount != 0}"
selection="#{testController.selectedRow}" noDataLabel="No results to show" var="test" rows="20"
style="width: 790px" selectionMode="single">
<a4j:ajax execute="#form"
event="selectionchange"
listener="#{testController.selectionListener}"
render=":res"/>
{columns to display}
</rich:extendedDataTable>
</h:column>
<a4j:outputPanel id="res">
<rich:panel header="Selected Rows:" rendered="#{not empty testController.selectedRows}">
<rich:list type="unordered" value="#{testController.selectedRows}" var="t">
<h:outputText value="#{t.name}"/>
<br/>
<h:outputText value="#{t.details}" converter="#{testConverter}"/>
</rich:list>
</rich:panel>
</a4j:outputPanel>
</h:panelGrid>
<rich:contextMenu target="testTable" mode="ajax" id="contextMenu">
<rich:menuItem label="Edit" render="popupEdit" oncomplete="#{rich:component('popupEdit')}.show();" mode="ajax"/>
</rich:contextMenu>
<rich:popupPanel id="popupEdit" modal="true" autosized="true" resizeable="false" moveable="false" domElementAttachment="form">
<rich:hotKey key="esc" onkeyup="#{rich:component('popupEdit')}.hide(); return false;"/>
<f:facet name="header">
<h:outputText value="Edit Test"/>
</f:facet>
<f:facet name="controls">
<h:outputLink value="#" onclick="#{rich:component('popupEditar')}.hide(); return false;">
<h:graphicImage value="/resources/css/images/fechar_janela.png" width="20" height="20"/>
</h:outputLink>
</f:facet>
<h:panelGrid id="popupEditContent" columns="2">
... {display of info}
<a4j:commandButton value="Salvar" actionListener="#{testeController.update()}" render="tabelaTestes, contextMenu"/>
<h:panelGroup id="messagePanel" layout="block">
<rich:messages ajaxRendered="true" />
</h:panelGroup>
</h:panelGrid>
</rich:popupPanel>
And now the strange behaviour (using NetBeans):
Deploy the app from NetBeans;
Open the URL of the deployed project on browser (Firefox) . The <a4j:ajax> inlined in the table doesn't work, I know this because the 'testController.selectionListener' is not called and the details are not displayed (it sets the attribute current in the backing bean). The contextMenu works but the popupPanel shows null or empty properties in all fields (the current attribute is not set);
Go back to the IDE, remove all the <rich:popupPanel> section and save the file;
Back in the browser, hit F5 and click a row. Now the <a4j:ajax> works and calls testController.selectionListener, showing the details in <a4j:outputPanel>. The context menu works but (obviously) the panel does not pop;
In the IDE, put back the <rich:popupPanel> section and save the file;
Now refresh the page again, and everything works, details are shown and the Edit pop up shows the right info of the selected row.
I have tried deploying it without the <rich:popupPanel> section and the selecionListener gets called. I think that the problem is deploying the page with both <a4j:ajax> and <rich:popupPanel> sections, hence the "conflict".
I took the structure from the richfaces showcase and made changes. I noticed that in the showcase, the <rich:popupPanel> is placed outside the <h:form> tag, wich in my project is placed in the template.xhtml (so a topmenu page works). Is it possible that the error is caused by this placement?
Could this be considered a bug to file in the richfaces project or am I missing something there?
Is there a workaround or solution?
Thank you very much!
I think I have solved it. I set the id attribute to "form" in the <h:form> tag, in template.xhtml, so now it looks like this:
<h:body>
<h:form id="form">
<div id="top" class="top">
<ui:insert name="top">Top</ui:insert>
</div>
<div id="content" class="center_content">
<ui:insert name="content">Content</ui:insert>
</div>
</h:form>
</h:body>
It was the only change I made and now all the components work at first post-deploy.
Edit: Found the solution when searching for another problem: JSF action call on secon click

hide component, then show it, values are not saved

I have a JSF 2.0 web app with ajaxified tabs.
To switch tabs I show one and hide the others (Either with a conditional render="#{x==y}" or with with display:none/block through conditional styleClass`ing.
In either case I get the tabs to show or hide correctly.
The problem is that the values entered in the input boxes are not retained throw a hide/show of a tab (In other words, if you enter some values in tab 1, go to tab 2 and back to tab 1, the values are not retained).
I use this <f:ajax> tag on tab selection (ignited by a hash change event)
<h:form id="processFragment" prependId="false" class="hide">
<h:inputText id="fragment" value="#{fbean.fragment}">
<f:ajax event="change" execute="contentSection" listener="#{fbean.processFragment}"
render="contentSection" />
</h:inputText>
</h:form>
<div>
<h:form id="contentSection">
<ui:insert name="content" />
</h:form>
</div>
Thanks!
The code the display the tab bar and the tab contents:
<ui:define name="content">
<f:view>
<h:panelGroup styleClass="navBar">
<ul>
<ui:repeat value="#{hello.tabList}" var="tab">
<li onclick="window.location='\##{tab.tabHash}'"><h:panelGroup
styleClass="#{hello.chose == tab.tabHash?'activeTab':''}">
<h:outputText value="#{tab.tabName}" />
</h:panelGroup>
</li>
</ui:repeat>
</ul>
</h:panelGroup>
<h:panelGroup id="contentPanels" styleClass="tabContentBar">
<c:forEach items="#{hello.tabList}" var="tab">
<h:panelGroup rendered="#{hello.chose == tab.tabHash}">
<!-- <h:panelGroup styleClass="#{hello.chose == tab.tabHash?'shownTabContents':'hiddenTabContents'}"> -->
<ui:include src="#{tab.tabFile}" />
</h:panelGroup>
</c:forEach>
</h:panelGroup>
</f:view>
</ui:define>
Finally, the contents of the specific tab:
<h:outputText value="TESTING 1" />
<h:panelGroup styleClass="formField">
<h:outputText value="Enter Value:" />
<h:inputText value="#{general.name}" />
</h:panelGroup>
UPDATE
Just noticed that even if I don't hide the tabs and press a button, the value is reset. Investigating...
The values will only be retained if you use a view scoped bean and the desired form is been submitted to the server side during (or right before) tab navigation.
As an alternative, you could render all tabs at once and use only JS/CSS to show/hide tab contents. CSS-hidden inputs will still be submitted to the server side.

Resources