Richfaces modal panel and a4j:keepAlive - jsf

I've got unexpected problems with richfaces (3.3.2) modal panel. When i try to open it, browser opens two panels instead of one: one is in the center, another is in the upper left corner. Besides, no fading happens. Also i have three modes: view, edit, new - and when i open my panel it should show either "Create new..." or "Edit..." in the header and actually it shows but not in the header as the latter isn't rendered at all though it should, because i set proper mode in action before opening this modal panel. Besides it works fine on all other pages i've made and there are tens of such pages in my application. I can't understand what's wrong here. The only way to fix it is to remove <a4j:keepAlive/> from the page that is very strange, imho.
I'm not sure if code will be usefull here as it works fine everywhere in my application but this only case. So if you put it on your page it will probably work without problems. My only question is: are there any hidden or rare problems in interaction of these two elements (<rich:modalPanel> and <a4j:keepAlive>)? Or shall i spent another two or three days searching for some wrong comma, parenthesis or whatever in my code? :)
For most curious. Panel itself:
<!-- there's no outer form -->
<rich:modalPanel id="panel" autosized="true" minWidth="300" minHeight="200">
<f:facet name="header">
<h:panelGroup id="panelHeader">
<h:outputText value="#{msg.new_smth}" rendered="#{MbSmth.newMode}"/>
<h:outputText value="#{msg.edit_smth}" rendered="#{MbSmth.editMode}"/>
</h:panelGroup>
</f:facet>
<h:panelGroup id="panelDiv">
<h:form >
<!-- fields and buttons -->
</h:form>
</h:panelGroup>
</rich:modalPanel>
One of the buttons that open panel:
<a4j:commandButton id="addBtn"
reRender="panelHeader, panelDiv"
value="#{form.add}"
oncomplete="#{rich:component('panel')}.show()"
action="#{MbSmth.add}"
image="create.gif"/>
Action invoked on button click:
public void add() {
curMode = NEW_MODE; // initial mode is VIEW_MODE
newSmth = new Smth();
}
Mode check:
public boolean isNewMode() {
return curMode == NEW_MODE;
}
public boolean isEditMode() {
return curMode == EDIT_MODE;
}

remember that the modalPanel is always there, but it's hidden. i think the keepAlive is showing this at all times.

Add domElementAttachment="parent" parameter to rich:modalPanel, and the editor will work fine.

Related

Close dialog prior to navigate away from the page

PrimeFaces: 7.0
JSF: 2.2.13
JBoss: 7.1
Java: 1.8
Chrome: 83.0.4103.116
I have a simple confirmation dialog to go to another page, there a reason for the action should be provided as a text.
It boils down to the following lines of code:
<p:dialog id="dlg" widgetVar="dlg" modal="true">
<h:form id="dlgForm">
<p:inputText id="reason" required="true" value="#{bean.reason}"/>
<p:message for="reason"/>
<p:commandButton id="proceed" value="Proceed" update="dlgForm" action="#{bean.action}"/>
<p:commandButton id="cancel" value="Cancel" resetValues="true" onclick="PF('dlg').hide()">
<p:ajax update="dlgForm" resetValues="true"/>
</p:commandButton>
</h:form>
</p:dialog>
And the bean:
#ManagedBean(name = "bean")
#SessionScoped
class Bean {
public String processGrundFuerExportDlg() {
PrimeFaces.current().executeScript("PF('dlg').hide()");
return "other_page";
}
}
My requirements:
Dialog opens with the empty 'reason'-inputText.
If 'cancel' is pressed: dialog should close
If 'proceed' is pressed:
If reason is not empty: close dialog and navigate to the 'other_page'
If return is empty: show the error message and don't close the dialog
My problem with this code: the line
PrimeFaces.current().executeScript("PF('dlg').hide()");
seems to be executed AFTER the current page being left resulting in 'dlg' not being found (JavaScript error).
The not properly closed dialog produces a nasty side effect: After returning to my first page later on, the dialog overlay stays active and inputText elements can't be activated with the mouse (TAB works). Overlay logic in the event loop blocks mouse clicks to from being passed to the components on the page.
My question:
How this standard scenario should be properly implemented with JSF and PrimeFaces?
If Upgrade to other versions is required, are there some workaround for removing stale overlays without upgrading?
Disclaimer: I studied many related questions on StackOverflow and tried all proposed solutions without success. For example this one: Keep p:dialog open when a validation error occurs after submit
You won't be having this problem if you would redirect to the new page instead of triggering an Ajax update.
You can simply add ?faces-redirect=true to your returned string, so:
return "other_page?faces-redirect=true";
Or, if you are using faces-config, add <redirect/> to the <navigation-case>.
Then you can remove the script from your bean where you try to close the dialog.
See also:
How to navigate in JSF? How to make URL reflect current page (and not previous one)
If 'proceed' is pressed:
If reason is not empty: close dialog and navigate to the 'other_page'
If return is empty: show the error message and don't close the dialog.
All this above is handled with required true on reason inputText. If reason is empty action in proceed commandButton won't start.
You don' need to close your dialog before you are navigating to other page.

Primefaces autoUpdate only works once

I have a page with different calculations, which are done by ajax.
At the end of the page there should be a hint text, which is updated after each calculation.
For this I use the autoUpdate feature of Primefaces.
When I load the page initially the text is displayed correctly. Also after the first calculation the text is refreshed correctly.
But if I do further calculations, the text will not be changed anymore, no matter which value balanceController.getBalance() returns.
When I debug my code I see that balanceController.getDetails() runs correctly and also returns the desired text. Only the content on my page is not refreshed. When I manually reload the page (with the browser) the correct text appears.
What could be the cause that <p:autoUpdate/> is only executed during the first calculation and updates the tab content?
balancePage.xhtml
<p:tab title="Further details" rendered="#{balanceController.showDetails()}">
<p:autoUpdate/>
<h:outputText value="#{balanceController.details}"/>
</p:tab>
BalanceController.java
public String getDetails() {
if ( getBalance() >= 0 ) {
return "Your current balance is: " + Double.toString(getBalance());
} else {
return "Your credit has been used up!";
}
}
In general a p:tab is not updateable, as the one who renders the p:tab is the parent component. Probably a p:accordionPanel or p:tabView.
So you can either move the p:autoUpdate to the parent component or move it inside the h:outputText.
NOTE: you probably need to add a id to the h:outputText as only components with rendered id are updatetable and h:outputText skips rendering the id when no id attribute is explicitly set.
Its also possible to solve it by wrapping it a p:outputPanel:
<p:tab title="Further details" rendered="#{balanceController.showDetails()}">
<p:outputPanel>
<p:autoUpdate/>
#{balanceController.details}
</p:outputPanel>
</p:tab>
I removed the h:outputText by performance reasons. IMO one should not use h:outputText for simple text (escape is not set to false) as this creates a UICompoment on the server side, which is not required.

h:commandLink inside richfaces dataTable not working properly after pressing browser back button

After I've done some investigation on such issue online, I am still not able to find a proper solution.
The tech stack I have to use here is JSF 1.x, JBoss Seam 2.2.x and richfaces 3.3.x. So the scenario is:
UI
The page contains two main parts, the upper one is providing some criteria for users to search results, and the lower one is to display the results.
Here I am using richfaces.dataTable to populate the results. We also provide the link to load the details of a result item (h:commandLink). The dataTable of course is initially not shown up using rendered attribute of h:panelGroup.
It looks like:
<h:panelGroup rendered="#{results.size gt 0 and not showDetail}">
<rich:dataTable
id="results-table"
value="#{results}"
var="row"
rows="#{rowPerPage}"
styleClass="table"
rendered="#{not empty requests}">
......
<rich:column>
<f:facet name="header">
Action
</f:facet>
<h:commandLink value="DETAILS"
action="#{viewBean.showDetailContext(row)}"
styleClass="link">
</h:commandLink>
</rich:column>
......
</rich:dataTable>
</h:panelGroup>
ViewBean
Code:
#Scope(ScopeType.CONVERSATION)
#Name("result.view")
public class ResultView {
public void showDetailContext(T detailContext) throws Exception {
_detailContext = detailContext;
initListDetails();
setShowDetail(true);
}
protected void initListDetails() throws Exception {
//......
}
}
After doing some search, the UI will be like:
View with Results
So at this moment, users can click the "Details" link and navigate to the detail view like:
Details View
The problem now is when we click the browser back button, we go back to the previous "View with Results" and if users click the Details link of a different item, the Details View will still display the previous detail information as highlighted in the screenshot.
Any advice is highly appreciated.

PrimeFaces autocomplete: itemSelect versus change events

I need to trigger an ajax update upon change to a text box, which is a <p:autoComplete> component. I have observed that if the user opts to type the text manually, the event is a change, whereas if the user clicks one of the suggestions for the autocomplete, the event is itemSelect. So I added two <p:ajax> children to the input, each calling the same method and having the same update list, but one having event="change" and the other event="itemSelect".
However, I now discover something odd. For example, while in normal server mode I opened my page and typed "12". The autocomplete offered "1233" and "1234" as suggestions. I clicked "1233" and seemingly nothing happened. I clicked again and everything else filled in.
Repeat this in the debugger with a breakpoint on the event handler, and I can see that after the first click, the value is "12" and on the second click, it becomes "1233".
By switching commenting out the two different <p:ajax> I can see the different consequences. Without the "change" one, the handler is never called if the user selects an autocomplete suggestion, and without the "itemSelect" one, the handler is never called if the user types manually. But with both of them, there are two calls, and I'm sure there will be complaints about the double-click.
Some pseudo-code for those that like, first the xhtml:
<p:autoComplete id="itemId" value="#{myBacker.myBean.itemNumber}"
required="true" completeMethod="#{myBacker.idAutoComplete}">
<p:ajax event="itemSelect" update="beanDetails"
listener="#{myBacker.idChangeEventListener()}" />
<p:ajax event="change" update="beanDetails"
listener="#{myBacker.idChangeEventListener()}" />
</p:autoComplete>
<h:panelGroup id="beanDetails">
<h:panelGroup rendered="#{not empty myBacker.myBean.institutionName}">
<h:outputText value="#{myBacker.myBean.institutionName}" />
<!-- Continues with address, phone, etc.. -->
</h:panelGroup>
</h:panelGroup>
Then the Java backing bean code:
public void idChangeEventListener() {
myBean = myDAO.getDetails(myBean);
// another couple of init-type method calls
}
Give the parent tag a widgetVar attribute, then add this little attribute to the <p:ajax event="change" ...> child tag:
onstart="if(widgetVarName.panel.is(':visible')) return false;"
When the question was written, we were on PrimeFaces version 3.5, if I recall correctly. Since then, we need to update the solution to:
onstart="if(PF('widgetVarName').panel.is(':visible')) return false;"
with thanks to mwalter for pointing out the change.

JSF jumping to anchor right away

When a JSF commandLink is clicked, the scrollposition of the new page will be 0 - which is fine.
I noticed a strange behaviour with one of my jsf pages - but its acuallty quite hard to explain:
Clicking on a link in order to navigate "somewhere" usually freezes the page and when the new response is received, you'll end up on another page and the scrollposition gets reseted. This is fine.
In that particular case the "current" view is immediately scrolling to the top, once a commandlink is clicked, and THEN forwards to the desired navigation outcome.
Its like clicking on a plain link, that has just its anchor set to the top. <a href='#'>
What could be a possible reason for this? It feels very strange, if the page scrolls up the second you click on a link.
All pages have basically the same usage of commandlinks within datatables. No other page encounters that problems. The Controllers are different - but since the scrolling up is done within milliseconds, I dont think, that this is a server-side issue.
I noticed that jsf appends the # to all links, that are generated.
so, when I click on the link, I can see the url changing to .../page.xhtml# for a split second (the split second, the page scrolls up), and then getting re-jsft like .../page.xhtml?cid=4
edit:
for all my pages, the link looks like this:
SVA
However on that said page the return false; at the end is missing... which then makes the link behave like an anchor...
edit2:
The working-as-expected-links are generated, using <h:commandLink> - the ones that are making the page scroll up, are <p:commandLink>s (Primefaces). Indeed, replacing it, solves the issue, but still wonder what's different for the primefaces link.
edit3: Example
working as expected:
<h:form style="display:inline;">
<h:commandLink
action="#{processManagementController.unpinProcess(process)}">
<h:graphicImage
style="display:inline-block; height:16px; width:16px;"
value="/resources/img/pinned.png"
title="Click to unpin this process" />
</h:commandLink>
</h:form>
causes immediate scrolling:
<h:form style="display:inline;">
<p:commandLink ajax="false"
action="#{processManagementController.unpinProcess(process)}">
<h:graphicImage
style="display:inline-block; height:16px; width:16px;"
value="/resources/img/pinned.png"
title="Click to unpin this process" />
</p:commandLink>
</h:form>
It's not scrolled to top due to href="#", but because of the synchronous postback (which results in a complete reload of the page!). The both examples in your "edit3" still scrolls to top for me.
Nest <f:ajax> in the <h:commandLink>, or set ajax="true" on the <p:commandLink> to make it an asynchronous postback and thus get them to behave as intented.

Resources