Cannot show dialog in Primefaces RequestContext.execute() call - jsf

I have a tabview in which I want to refresh contents of one specific tab whenever user selects that tab. I also want modal dialog to pop up while tab is being refreshed.
Here is tabView with tabChange ajax event handler
<p:dialog widgetVar="statusDialog" modal="true" draggable="false" minimizable="false" appendToBody="true" closable="false" header="Processing..." resizable="false" maximizable="false">
<p:graphicImage library="assets" name="ajax-loader.gif"></p:graphicImage>
</p:dialog>
<p:tabView id="tabview" orientation="top" dynamic="false">
<p:ajax event="tabChange" listener="#{bean.tabChangeListener}"></p:ajax>
<p:tab title="tab1">
<ui:include src="/WEB-INF/views/tab1.xhtml"/>
</p:tab>
<p:tab title="tab2">
<p:remoteCommand actionListener="#{bean.refreshData}" update="someTab2ElementID" name="refresh" global="true" onstart="statusDialog.show()" oncomplete="statusDialog.hide()"/>
<ui:include src="/WEB-INF/views/tab2.xhtml"/>
</p:tab>
</p:tabView>
Here is tabChangeListener:
public void tabChangeListener(TabChangeEvent event) {
if ( event.getTab().getId().equalsIgnoreCase("tab2") ) {
RequestContext.getCurrentInstance().execute("refresh()");
}
}
The refresh remoteCommand is being called as expected, but my statusDialog is never shown. If the same remoteCommand is triggered by a button click the statusDialog appears. There are no errors in JavaScript console.
Why is statusDialog not shown when remoteCommand is triggered by RequestContext.execute() and how can I make it appear? I even tried adding statusDialog.show() to execute() but it didnt help.

I figured it out. Here is the solution:
<h:outputScript>
var blockCount=0;
function showStatus() {
if (blockCount==0) statusDialog.show();
blockCount++;
};
function hideStatus() {
blockCount--;
if (blockCount==0) statusDialog.hide();
};
</h:outputScript>
<p:ajaxStatus onstart="showStatus();" onsuccess="hideStatus();" onerror="blockCount=0;statusDialog.hide();errorDialog.show();"/>
<p:remoteCommand actionListener="#{bean.refreshData}" update="someTab2ElementID" name="refresh" global="true" onstart="showStatus()" oncomplete="hideStatus()"/>
Apparently the reason why my status dialog was not being shown is that another Ajax call finished and called statusDialog.hide() while my refresh() thing was going on. The JS code above maintains a counter of how many Ajax calls are in progress, and will only hide the status dialog when all calls have finished. Works as intended now!

If you want to show dialog when a specific tab is changed, you can inform a js function about, the tab selected control that it is 2 or not by adding a callback parameter via ajax response:
public void tabChangeListener(TabChangeEvent event) {
if ( event.getTab().getId().equalsIgnoreCase("tab2") ) {
RequestContext.getCurrentInstance().addCallbackParam("index", 2);
}
}
And use:
<p:ajax event="tabChange" listener="#{bean.tabChangeListener}"
oncomplete="showOrNot(xhr,status,args)"></p:ajax>
This will call the js function and it's going to control that the changed tab is 2 or not:
function showOrNot(xhr,status,args) {
if(args.index==2) {
statusDialog.show();
}
}
Or different approach is defining a value and using visible property of the p:dialog:
public void tabChangeListener(TabChangeEvent event) {
if ( event.getTab().getId().equalsIgnoreCase("tab2") ) {
this.condition=true;
}
}
And <p:dialog visible="#{bean.condition}"/>. And maybe you need to focus on your first approach and you can give an ID to p:dialog and update it via p:remoteCommand:
<p:remoteCommand actionListener="#{bean.refreshData}" update="someTab2ElementID dialog" name="refresh" global="true" onstart="statusDialog.show()" oncomplete="statusDialog.hide()"/>
Don't forget to give the exact client ID of the dialog in the update property of p:remoteCommand.

Related

submit button does not submit but only triggers InputText's onChange event

I am automatically selecting a value for radio button when the user types something in an input text using ajax.
The problem is: when the user types something in the input text and directly submits the form by clicking Get, the form does not submit but only the ajax is called because of the change event and the radio is updated.
A second click on the Get button, submits the form.
I also do not want to use keyup since it migth disturb the user while typing.
I use primefaces 5.1
here is my code:
<h:form id="myForm">
<p:selectOneRadio
value="#{myBean.include}" id="IncludeRadio">
<f:selectItem itemValue="Include" itemLabel="Include" />
<f:selectItem itemValue="Exclude" itemLabel="Exclude" />
<p:ajax process="#this" update="#form" />
</p:selectOneRadio>
<p:radioButton id="IncludeRadio0" for="IncludeRadio" itemIndex="0"/>
<p:radioButton id="IncludeRadio1" for="IncludeRadio" itemIndex="1"/>
<p:inputText
value="#{myBean.fieldValue}"
id="FieldValueInputText">
<p:ajax process="#this" update="#form" />
</p:inputText>
<p:commandButton id="GetButton"
action="#{myBean.execute}"
value="Get">
</p:commandButton>
</h:form>
and the bean:
#ManagedBean
#SessionScoped
public class MyBean {
public void setFieldValue(final String fieldValue) {
if (fieldValue != null && !fieldValue.trim().isEmpty()) {
if (!"Include".equals(getInclude())
&& !"Exclude".equals(getInclude())) {
setInclude("include");
}
} else {
setInclude("");
}
}
public void setInclude(String include) {
this.include = include;
}
public String getInclude() {
return this.include;
}
public void execute() {
// do something
}
}
submit button does not submit but only triggers InputText's onChange event
That happened because the blur event of the input field ajax-updates the submit button around the moment you click it. This way the JavaScript/Ajax logic associated with submit button is not guaranteed to work anymore, because the source element is removed from the DOM.
Make sure that you don't cover the submit button in the ajax update.
Instead of updating the entire form,
<p:ajax ... update="#form" />
update only the pieces which really need to be updated, which are only the inputs in your specific case:
<p:ajax ... update="IncludeRadio FieldValueInputText" />
Or if you'd rather like to not keep track of all those IDs when you have many inputs, grab PFS:
<p:ajax ... update="#(#myForm :input)" />

Displaying Primefaces confirmDialog from Backing Bean

I have a Primefaces datatable and when the user clicks on a row, I display the data to edit in a form.
If the user changes the data in the form and clicks on any other row i.e if there is dirty data, I need to popup a confirmDialog to show if the user wants to save the data / discard it.
The confirmDialog does not display when I try to execute it from backing bean.
Any help is appreciated!
I have implemented it as follows:
.xhtml:
<p:dataTable id="tsTableId" value="#{transactionSetBean.studentList}" var="tsRow"
selectionMode="single" selection="#{transactionSetBean.selectedEditRec}" rowKey="#{tsRow.id}" scrollRows="10">
<p:ajax event="rowSelect" listener="#{transactionSetBean.onRowSelect}" update=":transactionSetsForm:tsEntryFrmId">
</p:ajax>
..
</p:dataTable>
ConfirmDialog:
<p:confirmDialog widgetVar="dataChangeDlg" message="Save changes Or Cancel">
<p:commandButton value="Save Changes" oncomplete="PF('dataChangeDlg').hide();"
update=":transactionSetsForm:messages :transactionSetsForm:tsEntryFrmId"
action="#{transactionSetBean.updateRecord}" />
<p:commandButton value="Cancel" onclick="PF('dataChangeDlg').hide();"
</p:confirmDialog>
Backing Bean:
public void onRowSelect(SelectEvent event)
{
String actionName = ON_ROW_SELECT;
try
{
Student selectedObj = (Student)event.getObject();
if (selectedObj != null)
{
selectedEditRec = selectedObj;
}
// if data is changed then show the dataChange dialog
if (isDataChanged())
{
setShowDataChangedDialog(true);
RequestContext context = RequestContext.getCurrentInstance();
// execute javascript and show dialog
context.execute("PF('dataChangeDlg').show();");
}
}
catch (Exception e)
{
handleException(e);
}
}
RequestContext.getCurrentInstance().execute("PF('dataChangeDlg').show();");
<p:ajax event="rowSelect" listener="#{transactionSetBean.onRowSelect}" update=":transactionSetsForm:tsEntryFrmId">
works for me.
There must be another error. maybe isDataChanged is false, wrong component ids in update or something.
With PrimeFaces >= 6.2
PrimeFaces.current().executeScript("PF('dataChangeDlg').show()");

how to show loading dialogue while bean method working?

i have a commandbutton that when i click i activate a methode as an action but this action take same time like 10 second. in this time i want to show a dialogue that have as msg loading and to be closed automatiquly when the action is finished. i tryed this like that but doesnt work its apear with last message that confirm that the action is finished well.
in JSF code :
<p:dialog id="basicDialog4" header="Information" widgetVar="dlg1" visible="#{gestionduplanning.displaydialog4}" style="background-image: none;background-color: #ffffff;">
<h:panelGrid columns="1" cellpadding="5" id="pn13236549532">
<h:outputText value="Chargement..." style="font-size: 16px;font-family:Times New Roman;" />
</h:panelGrid>
</p:dialog>
<p:commandButton icon="ui-icon-disk" onstart="#{gestionduplanning.chargementstart()}" action="#{gestionduplanning.planificationmanualglobal(gestionduplanning.chefequipedateplanifequipe)}" update="basicDialog2 basicDialog3" />
JSF managed bean :
public void chargementstart()
{
displaydialog4=true;
}
public void chargementstop()
{
displaydialog4=false;
}
any solution to show the loading dialogue waiting the action finish ??
You should look into BlockUI compoent which helps to block the UI when ajax request is procesing
https://www.primefaces.org/showcase/ui/misc/blockUI.xhtml

How to create chrome like tabs with primefaces

There are buttons like chrome-firefox bookmarks(say "google","facebook","twitter"). What I want to do is when user clicks a button, its related tab will open. For example if user clicks google button, google tab will rendered.
I have created some tabs and binded these tab's "rendered" property. But the problem is when i close the tab, I couldn't change variable which binded to the tab's "rendered" property. For example when I open and close google tab and then click to openFacebookTab button, Google tab is also rendered with Facebook tab because renderGoogleTab still holds true.
Must I create tabs and tabview programmatically or is there an easy solution?
My view;
<p:commandButton value="openGoogleTab" actionListener="#{myController.openGoogle()}"/>
<p:commandButton value="openFacebookTab" actionListener="#{myController.openFacebook()}"/>
<p:tab id="googleId" closable="true" title="Google" rendered="#{myController.renderGoogleTab}"/>
<p:tab id="facebookId" closable="true" title="Facebook" rendered="#{myController.renderFacebookTab}"/>
My controller;
#Controller("myController")
#Scope("view")
public class MyController{
//some variables
openGoogle(){
renderGoogleTab = true;
}
openFacebook(){
renderFacebookTab = true;
}
//getter and setters
}
Try to modify your code as follow,
openGoogle(){
renderGoogleTab = true;
renderFacebookTab = false;
}
openFacebook(){
renderFacebookTab = true;
renderGoogleTab = false;
}
Not the best method probably, but one workaround is to place the tabs in two separate tabView components (as I understand you need to be able to open two tabs simultanously) and then add a tab close listener like in the showcase. Then in the listener set the corresponding render*Tab properties to false.
So the jspx would be somewhat like this:
<p:tabView>
<p:ajax event="tabClose" listener="#{myController.onGoogleClose}"/>
<p:tab id="googleId" closable="true" title="Google" rendered="#{myController.renderGoogleTab}"/>
</p:tabView>
<p:tabView>
<p:ajax event="tabClose" listener="#{myController.onFacebookClose}"/>
<p:tab id="facebookId" closable="true" title="Facebook" rendered="#{myController.renderFacebookTab}"/>
</p:tabView>
Another approach would be to add a client side listener which invokes a server side method when the user clicks the close button.

primefaces accordion panel within single form - validation only on opened tab

I have checked around but I didn't found a clear example on how to submit the accordion using a single form.
The problem I find is when I want to process (validate) only fields of the opened tab.
The structure of my page is as follows:
<h:form>
<p:accordionPanel activeIndex="#{bean.selectedTab}">
<p:ajax event="tabChange" listener="#{bean.tabChangeListener}"/>
<p:tab title="Tab1" id="t1">
<p:inputText id="reqField1" required="true"/>
</p:tab>
<p:tab title="Tab2" id="t2">
<p:inputText id="reqField2" required="true"/>
</p:tab>
</p:accordionPanel>
<p:commandButton update="list" immediate="true" actionListener="#{bean.addRecord}"/>
</h:form>
method:
#SessionScoped
public class Bean{
public void tabChangeListener(AjaxBehaviorEvent evt){
AccordionPanel panel = (AccordionPanel) evt.getComponent();
// getLoadedTabs() returns an empty list
String currentlyLoadedTabId = panel.getLoadedTabs().get(this.selectedTab).getClientId();
}
}
Is there anyway to specify the id of the currently opened tab as part of the process attribute in p:commandButton tag?
UPDATE
When Tab1 is open, on submit, I want to be validated only reqField1 and not reqField2. Viceversa, when Tab2 is open, I want to be validated only reqField2 and not reqField1.
Try this.
Bind the activeIndex of the accordionPanel to a backing bean int attribute
activeIndex="#{myBean.selectedTab}"
Get the id of the currently selected tab using the bound activeIndex. To do this in your actionListener, get a handle on the accordion panel
EDIT: Since your actionListener has been set to immediate, the activeIndex and selectedTab will need to be updated via ajax. Add the following <p:ajax/> to your accordionPanel
<p:ajax event="tabChange" listener="#{bean.tabChangeListener}" />
In your backing bean, you'll now have
public void (AjaxBehaviorEvent evt){
AccordionPanel panel = (AccordionPanel) evt.getComponent();
String currentlyLoadedTabId = panel.getLoadedTabs().get(this.selectedTab).getClientId();
}
Using the the id you got from 2 above, you can include that in the JSF list of things to be rerendered using ajax on the server side. In the same action listener method:
FacesContext.getCurrentInstance().getPartialViewContext().getRenderIds().add(currentlyLoadedTabId);
Alternatively, you might just consider placing a command button in each of those tabs and having a form in each tab as well. This way, each command button processes only it's own parent form

Resources