I'm using Primefaces for a project and I'm seeing bad results with IE vs chrome/firefox/safari in regards to modal Primefaces dialog windows and I think it has to do with form placement. In IE these dialogs dont appear, but I can see the transparency. In chrome/firefox they're fine. What is the best practice for the below situations:
List item base xhtml page that has one form. This page has several
links that open up dialogs who have their own ajax submit
(commandButton, commandLink) events.
Should the dialog be located within or outside the base xhtml page's form?
Should the dialog have its own form?
Below is an illustration:
<html>
<ui:composition>
<ui:define name="content">
<h:form id="xyz">
//main page content here, commandButtons, commandLinks...etc
</h:form>
<dc:zoomDialog/>
</ui:define>
</ui:composition>
</html>
<!-- zoomDialog maps to the below -->
<html>
<ui:component>
<h:form id="dialogFrm">
<p:dialog widgetVar="zoomDlg" modal="true" styleClass="dialog dialog2"
draggable="false" resizable="false" showEffect="fade"
hideEffect="fade">
//dialog content here, commandButton, commanLink...etc
</p:dialog>
</h:form>
</ui:component>
I don't see it in your example code but some time ago I had a similar problem. The reason was: nested forms (the same symptoms as you describe: all browser work, except IE). Nested forms are not valid html. Some browsers can handle it. IE cannot.
A good test is to put the whole html outpout (browser source, not the jsf source) into the W3C Html validator and analyze the results.
In the Primefaces showcase the h:form element is always inside the p:dialog. See this discussion.
Related
I'am a beginner in jsf and I want to open an html page in a p:dialog.
When I use the <ui: include> to display the page like this:
<p:dialog header="Dialog"
widgetVar="dlg"
resizable="false"
dynamic="true"
fitViewport="true">
<ui:include src="/resources/md.html" />
</p:dialog>
it works with no problem, but when I want to open the page in a specific anchor like this:
<p:dialog header="Dialog"
widgetVar="dlg"
resizable="false"
dynamic="true"
fitViewport="true">
<ui:include src="/resources/md.html#anchor" />
</p:dialog>
it doesn't work.
Can somebody help please.
Your attempt fails because your md.html is statically included inside 'parent' jsf page. Therefore only parent jsf page can be used to achieve 'go to anchor' functionality.
To achieve what you want with an included page inside p:dialog, I would use simple java script.
JS
Add this JS function to your parent jsf page (page where dialog is defined)
function gotoAnchor(anchorID) {
document.getElementById(anchorID).scrollIntoView();
}
XHTML
Add onShow attribute on p:dialog like this
<p:dialog ... onShow="gotoAnchor('anchorID')" ...>
<ui:include src="/resources/md.html" />
</p:dialog>
where anchorID is id of your anchor element inside md.html (in your example, its value is 'anchor').
On this way, when your p:dialog is shown, function gotoAnchor will be executed forcing page to scroll on required element.
This is another solution using iframe tag, it works perfectly:
<p:commandLink value="iframe" onclick="PF('dlg').show()" />
<p:dialog header="Dialog" widgetVar="dlg">
<iframe height="500" width="800" src="/md.xhtml#anchor"></iframe>
</p:dialog>
No js need.
The Primefaces Documentation states that the following code will be invalid due to the fact that every layoutUnit needs its own form:
<p:layout fullPage="true">
<h:form>
<p:layoutUnit position="north">
<p:inputText value="#{testBean.input1}" />
</p:layoutUnit>
<p:layoutUnit position="center">
<p:inputText value="#{testBean.input2}" />
<p:commandButton value="save" action="#{testBean.save}" />
</p:layoutUnit>
<p:layoutUnit position="south">
<p:inputText value="#{testBean.input3}" />
</p:layoutUnit>
</h:form>
</p:layout>
However, when I nest p:layout inside of a form, the code works without any problem:
<h:form>
<p:layout fullPage="true">
<p:layoutUnit position="north">
<p:inputText value="#{testBean.input1}" />
</p:layoutUnit>
<p:layoutUnit position="center">
<p:inputText value="#{testBean.input2}" />
<p:commandButton value="save" action="#{testBean.save}" />
</p:layoutUnit>
<p:layoutUnit position="south">
<p:inputText value="#{testBean.input3}" />
</p:layoutUnit>
</p:layout>
</h:form>
What is the explanation for that behaviour? Can my approach of having just a single form tag outside of p:layout cause problems at some time point?
The PrimeFaces documentation does indeed state on Page 309 of the 6.1 documentation
When working with forms and full page layout, avoid using a form that contains layoutunits as generated dom may not be the same. So following is
invalid.
And in that they reference your first example. It is technically not invalid but due to the way the layout component renders the html needed in the browser (and maybe client-side does dom manipulation) to get the good full page experience, it might (will? never tried it myself) result in unexpected behaviour.
They also state
A layout unit must have it’s own form instead, also avoid trying to update layout units because of same reason, update it’s content instead.
'Must have' (emphasis above is mine) is to strong here, they'd better have stated
give each layout unit its own form if a form is needed in the layout unit.
A full form around the full page layout might work now assuming the layout will not mess with things and e.g. add parts to the surrounding body tag (if it does do dom manipulation to achieve a certain behaviour), but I doubt they'd give you guarantees. An additional reason to not do it like you ask might be that you can run into nested forms when developers of 'partial pages' a not fully aware of the 'god form'. So I would advise against it.
So if e.g. the north and south layoutunit contain sort of fixed functionality (header with search, footer with some features) then put a h:form directly in the layout unit. If the center part contains dynamic things e.g. a ui:include, put the `h:form in the included parts.
See also:
How to use <h:form> in JSF page? Single form? Multiple forms? Nested forms?
How to ajax-refresh dynamic include content by navigation menu? (JSF SPA)
I have a strange problem with commandButton on JSF pages using both primefaces commandButton or XHTML CommandButton. This is my code:
<div id="outer">
<h:form>
<p:commandButton action="#{logoutBean.logout}" value="Logout" /> (1)
</h:form>
</div>
<div id="footer">
<h:form>
(2)
</h:form>
</div>
/* these are inherited from upper code ... */
</div>
</div>
I want to move(cut&paste) the instruction 1 in the point 2 and delete it from point 1 ... But if I do this, the page falls in error. Why??
I found this problem with every commandbutton I have on my project.
How can I do this??? the strange thing is that if I comment the new-line at point 2 (so the program should return working well) it doesn't. To make the program rerun I have to delete literally the newline completely.
I've implemented a p:commandButton to update the contents of a table when it is clicked. I think this is working (although It isn't properly tested) but the more immediate issue is as follows.
Bug
Before the request, the title bar looks like this:
And after I hit the refresh button on the right, the page re-renders as follows:
Attempts to solve
The following is the current code for my p:commandButton:
<p>
<p:commandButton oncomplete="eventFeedsDialog.show()" update=":eventFeedsForm" id="feedsRefresh" icon="ui-icon-refresh" title="Refresh page" style="height:40px; width:40px; float:right;">
<f:setPropertyActionListener value="#{true}" target="#{searchBean.refresh}"/>
</p:commandButton>
</p>
The eventFeedsDialog is the p:dialog element that this button is wrapped in, which is further wrapped in a h:form element. Here is the declaration of the eventFeedsDialog element:
<p:dialog id="eventFeedsDialog" header="Feeds" widgetVar="eventFeedsDialog" resizable="false" width="1000"
styleClass="dialog">
I've tried changing the oncomplete attribute to point at the h:form instead of the dialog, but it appears not to have worked. I thought up a hack, whereby I append a mountain of spaces in the header attribute, but that is horrendously ugly.
I've not found anything on google like this, so I was wondering if you guys have any ideas?
I'm using Primefaces 3.3.1 and have question.
I have p:commandButton inside p:column of p:dataTable. I can show overlay menu when button is clicked with xhtml shown below.
<p:commandButton id="btnID" icon="ui-icon-circle-triangle-s" style="height: 16px;">
<f:setPropertyActionListener value="#{searchItem}" target="#{bean.selectedSearchItem}" />
</p:commandButton>
<p:slideMenu overlay="true" trigger="btnID" my="left top" at="left bottom"
model="#{bean.menuModel}"/>
In this case, bean.menuModel can return menu data instantly. But I have another case also which pre-procsessing is required to make menu data ready. So I have this one too.
<p:commandButton ajax="true" id="historyButton" action="#{bean.getHistory()}"
icon="ui-icon-note" style="height: 16px;"
onstart="workingDialog.show();"
oncomplete="workingDialog.hide(); historyMenu.show();">
<f:setPropertyActionListener value="#{searchItem}" target="#{bean.selectedSearchItem}" />
</p:commandButton>
<p:menu overlay="true" widgetVar="historyMenu" my="left top" at="left bottom"
model="#{searchBean.menuModel}"/>
What I meant is, when button is clicked, it calls bean.getHistory() which starts loading menu data for that row, and show modal dialog with circling icon. When loading is finished, dialog will go away and overlay menu will be shown. What I can't do is a last part of this scenario. Above code fires exception.
java.lang.NullPointerException
javax.faces.component.UIComponentBase.findComponent(UIComponentBase.java:561)
org.primefaces.component.menu.BaseMenuRenderer.encodeOverlayConfig(BaseMenuRenderer.java:138)
org.primefaces.component.menu.MenuRenderer.encodeScript(MenuRenderer.java:45)
org.primefaces.component.menu.BaseMenuRenderer.encodeEnd(BaseMenuRenderer.java:39)
javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:875)
javax.faces.component.UIComponent.encodeAll(UIComponent.java:1763)
javax.faces.component.UIComponent.encodeAll(UIComponent.java:1759)
Code shown below works fine, without menu related code.
<p:commandButton ajax="true" id="historyButton" action="#{searchBean.getHistory()}"
icon="ui-icon-note" style="height: 16px;"
onstart="workingDialog.show();"
oncomplete="workingDialog.hide();">
<f:setPropertyActionListener value="#{searchItem}" target="#{bean.selectedSearchItem}" />
</p:commandButton>
I guess this is easy question for experts. How can I open overlay menu from oncomplete?
Thanks in advance.
I could not find a solution for this issue but I came up with conclusion that what I wanted to do is not a good idea with the environment I'm working on.
First, I noticed that menu gets data from bean when row of data table is populated, not when menu is shown. And there is no lazy loading mechanism for menu. So button click -> get data for menu from server -> open menu cannot be done as I expected (at least it seems to me).
Second, I noticed putting menu in DataTable (under TabView in my case) causes very strange problem. When I update DataTable, some ajax related function stops working. I can't explain this problem to make you understand or believe, but app I'm working on is having this problem.
So, I gave up putting menu in DataTable in my app. Thank you for your attention.
I accept this answer not to lower my already LOW accept rate.