How to show ajaxstatus for dynamic Primefaces components - ajax

I have noticed that pretty much all PF components that have 'dynamic' attribute set to 'true' will only show up after a short delay (which is understandable), and also will not trigger ajax start/stop event.
This is my (perfectly working) Ajax status component, actual dialog contents omitted for brevity:
<p:ajaxStatus onstart="statusDialog.show();" onsuccess="statusDialog.hide();" onerror="errorDialog.show();"/>
This is a dynamically loaded dialog. It needs to get data from backing beans:
<p:dialog modal="true" widgetVar="confDialog" position="center" id="confD" dynamic="true">
<p:panelGrid>
<p:row>
<p:column>
<h:outputText value="Date"></h:outputText>
</p:column>
<p:column>
<h:outputText value="#{myBean.currentDate}">
<f:convertDateTime locale="#{myBean.currentLanguage}" type="both" dateStyle="full" timeStyle="full" timeZone="#{myBean.currentTimeZone}"></f:convertDateTime>
</h:outputText>
</p:column>
</p:row>
</p:panelGrid>
<p:commandButton value="Close" type="button" onclick="confDialog.hide();">
</p:commandButton>
</p:dialog>
A commandbutton that does something and displays dynamically loaded confirmation dialog:
<p:commandButton value="Do it" type="submit" ajax="true" process="#form"
action="#{bean.processForm}"
oncomplete="if(!args.validationFailed){confDialog.show();}"
update="confD #form"/>
Ajax status dialog is displayed while the commandbutton submits the data to backing bean and gets data back. Then ajax status dialog disappears, there is a delay of 1-2 seconds, and confirmation dialog is shown.
The same happens with dynamically loaded tabs (in PF tabView component).
Why isn't my ajax status dialog displayed during dynamic component load? How can I show it?
EDIT:
thanks to #partlov I figured out a solution without overriding PF function, by adding JQ ajax start/stop handler to the dynamically loaded dialog:
jQuery(document).ready(function() {
confDialog.getJQ().ajaxStart(function(){statusDialog.show()});
confDialog.getJQ().ajaxStop(function(){statusDialog.hide()});
});

As written in Primefaces documentation <p:ajaxStatus> just intercepts global AJAX requests, and this request is not global. There is no easy way to do this what you want. As time of loading of dialog is short I really don't see point for this. Only solution, as I think, is to overload Primefaces dialog JavaScript methods.
Primefaces calls loadContents() method when dialog content is loaded so you can override this method for this. I don't advice you to do that, because this is undocumented and can be changed in future versions of Primefaces:
jQuery(document).ready(function() {
var oldLoadContents = PrimeFaces.widget.Dialog.loadContents;
PrimeFaces.widget.Dialog.loadContents = function() {
statusDialog.show();
oldLoadContents();
}
});
This should show your dialog on dynamic loading. You can use onShow attribute of p:dialog to close your dialog:
onShow="statusDialog.hide()"

Related

p:ajax blur event on p:inputText is not invoked when p:commandButton is clicked

I want to pass data to back bean through ajax call on command button click.
I have a form with couple of input text fields where each field is having ajax blur event.
Every thing is working fine in happy flow except in the flowing scenario.
Ajax blur event is invoking when i directly clicking on submit which is suppose to be happen before submit click, hence i should make another click on submit button to invoke ajax call to save my form.
Here is the code.
Input text fields:
<p:inputText id="txt_name"
value="#{partnerVO.partnerName}"
required="true" maxlength="30"
rendered="#{!partnerVO.isReadOnly}">
<p:keyFilter regEx="/[A-Za-z0-9#.,&- ]/i"
for="txt_name" preventPaste="false" />
<p:ajax update="txt_name" event="blur" />
</p:inputText>
<p:inputText id="txt_assigned"
value="#{partnerVO.assignedName}"
required="true" maxlength="30"
rendered="#{!partnerVO.isReadOnly}">
<p:keyFilter regEx="/[A-Za-z0-9#.,&- ]/i"
for="txt_assigned" preventPaste="false" />
<p:ajax update="txt_assigned" event="blur" />
</p:inputText>
Command Button:
<p:commandButton id="btn_save"
title="Save"
value="#{lbl['tpdetails.remove.additional.address']}"
update="#form" process="#this"
action="#{partnerDetailsController.save}">
</p:commandButton>
I'm using JSF 2.2
Please provide some suggestions to overcome this strange behavior.
Note: omitted form related code here.

How to submit JSF PrimeFaces form with selectBooleanCheckbox without refreshing the page?

I'm using JSF with PrimeFaces to make an application as an assignment for college. I'm struggling to get something working. I'm using PrimeFaces and I have a tabview which contains 5 tabs. In one of those tabs I have a dataTable which has several rows and columns. This all works fine, but the problem is that I want to submit the form without rerendering the (entire page). The thing is, every column in the dataTable has a selectBooleanCheckbox, and when that checkbox is selected, a button should disappear. If it's unselected the button should appear. This works fine with onchange="this.form.submit()" or onclick="this.form.submit()" but it refreshes the entire application, and it causes the first tab to be selected, rather than the one I was at. So I'm looking for a solution to be able to submit and re-render some stuff without refreshing the entire program. This is my code:
<body>
<h:form id="customerForm">
<p:dataTable id="customerlist" var="c" value="#{customerBean.customerList}">
<p:column>
<f:facet name="header">Select</f:facet>
<center>
<p:selectBooleanCheckbox value="#{c.selected}" onchange="this.form.submit()"/>
</center>
</p:column>
</p:dataTable>
<h:commandButton id="testtest" value="test" rendered="#{customerBean.numberSelected() == 0}"/>
</h:form>
</body>
I removed most of the columns for the sake of simplicity. What is the solution to this? I've tried using ajax, but that didn't work
<p:selectBooleanCheckbox value="#{c.selected}">
<f:ajax event="click" execute="#form" render="#none"/>
</p:selectBooleanCheckbox>
Do you really need to submit the whole form? If it's enough that the view is being rerenderd try just to update the form. For that you can use the primefaces ajax event.
<p:selectBooleanCheckbox value="#{c.selected}">
<p:ajax update="#form"/>
</p:selectBooleanCheckbox>
If this does not work, please tell us what "..ajax, didn't work" exactly mean. Is there any POST Request submitted? Is any Action/Setter called?

Validation message not rendered in dialog using jsf

<p:dialog widgetVar="dlgEdit" header="Add New Status">
<h:form id="editFrm">
<h:panelGrid columns="3" id="pnlEdit">
<p:outputLabel value="Status"/>
<p:inputText id="txtStatus" required="true"/>
<p:message for="txtStatus" />
</h:panelGrid>
</p:dialog>
This is a primefaces message tag which is not rendered in dialog.
And dialog is hide on onComplete event..
How can I RENDER validation message in DIALOG using jsf?
Thank for any suggestion !
In your submit button add these entries
ajax="true" update=":#{p:component('message')}" oncomplete="if(!args.validationFailed)dlgEdit.hide();"
This will print your message in the same dialog.
Is it ok if your validation message is displayed in the parent page?
If yes, in that case you can throw a feedback error message. This will be picked up by the p:message in your parent page.
If no, please refer to this question below in this link for dialog window with ajax=false situation.

f:ajax does not update t:dataTable on complete

I have a JSF search command button and a tomahawk dataTable that showing the result from a search. When clicking on the command button, the dataTable should output the search result. Anyway, since I use the JSF Ajax, the dataTable doesn't show. I am just wondering whether JSF Ajax cause the problem?
Here is the problematic code that cause the table now render:
<h:commandButton id="search" value="#{msg.Label_Search}" action="#{theBean.doSearch}">
<f:ajax render="searchStatus" execute="#form" />
</h:commandButton>
<h:outputText id="searchStatus" value="Loading data now..." rendered="#{theBean.searchingNow}" />
<h:panelGroup id="searchResultTable">
<t:dataTable ... />
</h:panelGroup>
*Take note on this. If the ajax code were removed. It is working fine.
You're only updating the searchStatus, not the searchResultTable when the ajax request completes. So the enduser will indeed never see a visual change in the HTML representation of the searchResultTable.
Fix the <f:ajax render> accordingly so that the searchResultTable is also really updated:
<f:ajax render="searchStatus searchResultTable" execute="#form" />

Primefaces blockUI stops working after ajax update

I am trying to create a datatable that displays a blockUI whenever it is busy, and I have been mostly successful. It now grays out and shows "Loading..." whenever I click either of two commandButtons, sort the datatable by clicking on a header, or page through the datatable. You can see the code for it below.
The problem is that after I have used one of the commandButtons (which runs an ajax update on the blocked element), subsequent actions do not trigger the blockUI (until I refresh the page). For example:
Load page
Click a datatable header - blockUI appears until table is finished sorting
Click one of the datatable page navigation buttons - blockUI appears until the page is loaded
Click one of the commandButtons - blockUI appears until the button's actionListener has finished
Click a datatable header - table sorts, but blockUI does not appear.
Click one of the datatable page navigation buttons - page loads, but blockUI does not appear
Click one of the commandButtons - actionListener runs and table updates, but blockUI does not appear
Reload the page - everything works properly again
Changing the commandButtons' update="" attribute to ajax="false" causes the sorting/paging to always display the blockUI, but the commandButtons to never display the blockUI.
Any ideas?
<div class="buttonDiv">
<p:commandButton ... update="resultsPanel" id="submitButton" ... />
...
<p:commandButton ... update="resultsPanel" id="resetScenarioButton" ... />
</div>
<p:panel header="Results Grid" id="resultsPanel">
...
<p:dataTable ... id="VAResults" ... >
...
</p:dataTable>
....
</p:panel>
<p:blockUI block="resultsPanel" trigger="submitButton, resetScenarioButton, VAResults">
Loading...
</p:blockUI>
The trigger attribute binds jQuery listeners on the specified elements. However if you update an element the binding gets lost. I don't know if it works, but you could try moving the <p:blockUI inside the resultsPanel. I suspect that when you update the panel the blockUI gets updated too and thus re-binding the listener to the data table.
<p:panel header="Results Grid" id="resultsPanel">
...
<p:dataTable ... id="VAResults" ... >
...
</p:dataTable>
....
<p:blockUI block="resultsPanel" trigger="submitButton, resetScenarioButton, VAResults">
Loading...
</p:blockUI>
</p:panel>
I've had the same problem and kind of simillar scenario:
<p:dataTable>
....
<p:ajax event="rowSelect" update="buttons" global="false" onstart="blockMessageButtons.show();" oncomplete="blockMessageButtons.hide();"/>
</p:dataTable>
<p:outputPanel layout="block" id="buttons">
<!-- content to be blocked -->
</p:outputPanel>
<p:blockUI block="buttons" widgetVar="blockMessageButtons"/>
The problem was that panel buttons was both updated by ajax, and blocked by blockUI. I had to divide it in two:
<p:dataTable>
....
<p:ajax event="rowSelect" update="buttons-content" global="false" onstart="blockMessageButtons.show();" oncomplete="blockMessageButtons.hide();"/>
</p:dataTable>
<p:outputPanel layout="block" id="buttons-container">
<p:outputPanel layout="block" id="buttons-content">
<!-- content to be blocked -->
</p:outputPanel>
</p:outputPanel>
<p:blockUI block="buttons-container" widgetVar="blockMessageButtons"/>
#siebz0r already provided the explanation why blockUI stops working when a component is updated.
I am using a one blockUI element in the template for all other pages and thus don't want to include more blockUI elements.
If the blockUI element is updated as well one does not need to move the blockUI inside the component that will be updated.
Here is an example:
<p:panel id="surroundingPanel">
...
<p:commandButton value="ButtonName" styleClass="blockUi"
action="actionToBeExecuted" update=":surroundingPanel :blockUiBinding" />
</p:panel>
<p:outputPanel id="blockUiBinding">
<p:blockUI block=":elementToBeBlocked" trigger="#(.blockUi)">
Loading ...
</p:blockUI>
</p:outputPanel>
The element blockUiBinding can be located anywhere, as long as it can be updated. It is wrapping the blockUI element, because blockUI generates at least two different divs. So when the wrapping element is updated also the blockUI will be updated.

Resources