How to inject one JSF2 page into another with jQuery's AJAX - ajax

I'm using jQuery's .load function to load one JSF page into another.
This works really well until the loaded JSF page uses some AJAX functionality. When this happens, the parent JSF page's AJAX stops working. In fact, after the two pages are combined whichever page has its AJAX called next is the one that continues to work. The other page stops working. If I use the parent page first, the child breaks. If I use the child first, the parent breaks.
Am I doing something wrong? I'm guessing JSF isn't designed for this sort of behaviour and that's fine but then how do I go about doing what I want?
Basically, we have a report page. When the user clicks the link to a report we would like the report to load dynamically into the existing page. That way, the user doesn't experience a page refresh. It's a pretty slick behaviour BUT obviously isn't ideal due to the pages breaking.
I suppose I could do this with a page that contains every report in an outputpanel and then determine which one is rendered based on a value in the backing bean but I can see lots of occasions where I'd like to be able to "inject" one page into another (for dynamic dialogs for instance) and it would suck to have to keep everything in one giant template.
Has anyone else come across this sort of problem? How did you solve it?

Do not use jQuery.load(). It does not take JSF view state into account at all, so all forms will fail to work. Rather make use of <f:ajax> and rendered attribute instead. Here's a basic example:
<h:form id="list">
<h:dataTable value="#{bean.reports}" var="report">
<h:column>#{report.name}</h:column>
<h:column>
<h:commandLink value="Edit" action="#{bean.edit(report)}">
<f:ajax render=":edit" />
</h:commandLink>
</h:column>
</h:dataTable>
</h:form>
<h:form id="edit">
<h:panelGrid columns="3" rendered="#{not empty bean.report}">
<h:outputLabel for="name" value="Name" />
<h:inputText id="name" value="#{bean.report.name}" required="true" />
<h:message for="name" />
...
<h:panelGroup />
<h:commandButton value="save" action="#{bean.save}" />
<h:messages globalOnly="true" layout="table" />
</h:panelGrid>
</h:form>
You can if necessary split off the content into an <ui:include>.

Related

f:ajax render form component

I want to render a single component (h:selectManyCheckbox) inside a form based on a check-box that I select or not.
<h:form>
<h:selectBooleanCheckbox value="#{bean.var}">
<f:ajax event="click" render="employeeCheckboxes" />
</h:selectBooleanCheckbox>
<h:selectManyCheckbox
id="employeeCheckboxes"
value="#{bean.checkboxes}"
rendered="#{var}">
</h:selectManyCheckbox>
</h:form>
However, the component isn't re-rendered on selecting or deselecting the check-box. I can however re-render the whole form but I don't want that.
You can't reference a component in <f:ajax render> which is in first place never rendered in HTML output. The <f:ajax render> uses under the covers JavaScript document.getElementById() to find the HTML element in order to update it with the new HTML structure from the ajax response. However, if a JSF component is in first place never rendered in HTML output, then JavaScript can't find it anywhere either.
You need to wrap it in another component which is always rendered.
<h:form>
<h:selectBooleanCheckbox value="#{bean.var}">
<f:ajax render="employeeCheckboxesGroup" />
</h:selectBooleanCheckbox>
<h:panelGroup id="employeeCheckboxesGroup">
<h:selectManyCheckbox
id="employeeCheckboxes"
value="#{bean.checkboxes}"
rendered="#{bean.var}">
</h:selectManyCheckbox>
</h:panelGroup>
</h:form>
(note that I removed event="click" as it's the default already)
See also:
Why do I need to nest a component with rendered="#{some}" in another component when I want to ajax-update it?
Hi i think you missed managed bean name in
rendered attribute
of checkbox tag.

partial page rendering (PPR) with faces-redirect

I'm using PrimeFaces 3.5 and I faced a problem with partial page rendering. I need to load content from a Facelet file into "dynamic" part of a template.
index.xhtml:
<f:view>
<h:form id="form1">
<p:outputPanel layout="block">
<p:commandButton action="content-2?faces-redirect=false" update="display" />
</p:outputPanel>
<p:outputPanel id="display" layout="block">
content 1
</p:outputPanel>
</h:form>
</f:view>
content-2.xhtml:
<h:body>
content 2 loaded
</h:body>
When I click on the <p:commandButton>, then content-2.xhtml will be opened. However, this refreshes the whole page. The XML response contains like this:
<partial-response><changes><update id="javax.faces.ViewRoot">
When I change the action attribute to a method expression:
<f:view>
<h:form id="form1">
<p:outputPanel layout="block">
<p:commandButton action="#{myBean.increment}" update="display" />
</p:outputPanel>
<p:outputPanel id="display" layout="block">
#{myBean.count}
</p:outputPanel>
</h:form>
</f:view>
Then the display block updates as expected. The XML response contains like this:
<partial-response><changes><update id="form:display">
Why does the action="content-2?faces-redirect=false" way update the entire page?
I also tried to <ui:composition>, but in this case this reloads "static" part of template. I do not want it.
This is fully normal and expected behavior if you navigate to a different view by supplying a non-null outcome in the action attribute. JSF will then overrule the partial render with a render of #all. JSF/Facelets won't somehow automagically retain the common components in the tree as you seemed to expect. If you intend to dynamically change the component tree during a partial page rendering, then you need inside the <p:outputPanel id="display" layout="block"> either a dynamic include something like this (section is just an integer)
<ui:include src="section#{bean.section}.xhtml" />
or multiple conditionally rendered sections
<ui:fragment rendered="#{bean.section == 1}"><ui:include src="section1.xhtml" /></ui:fragment>
<ui:fragment rendered="#{bean.section == 2}"><ui:include src="section2.xhtml" /></ui:fragment>
<ui:fragment rendered="#{bean.section == 3}"><ui:include src="section3.xhtml" /></ui:fragment>
<ui:fragment rendered="#{bean.section == 4}"><ui:include src="section4.xhtml" /></ui:fragment>
Each has its own pros and cons depending on whether the include file contains form/input/command components and/or references view scoped beans. The <ui:include> runs namely during view build time like JSTL. See for more detail also JSTL in JSF2 Facelets... makes sense?
The presence of faces-redirect=false is not significant as it's the default already. If it were true, then a JavaScript window.location would be invoked on the target URL.

Command Link under tab using Ajax Primefaces

I know that this question may be similar to this one but I didn't understand the answer at all.
I am using a full page layout, in the left layout I have some nested accordion panels, tabs and command links. I want this links to update center layout content form.
Left Layout:
<h:form>
<p:accordionPanel>
<p:tab title="Parent Tab">
<p:accordionPanel>
<p:tab title="Child Tab">
<p:commandLink value="link" update=":contentform" />
</p:tab>
</p:accordionPanel>
</p:tab>
</p:accordionPanel>
</h:form>
Center Layout:
<h:form id="contentform">
<ui:include src="#{layoutUI.viewId}" />
</h:form>
And a simple explanation will help cause the similar question lacks in that :(
The proper use of the built in Ajax functionality of the p:commandLink component is to specify that the link will invoke an Ajax call with the ajax attribute.
<p:commandLink value="link" ajax="true" update=":contentform" />
Using the : in front will signify that you are looking for the ID of a component on the ViewRoot rather than its direct Naming Container so this is correct. The only thing missing is the ajax attribute.

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" />

JSF 2, ajax input field behaves differently in firefox 10 and ie9

When cursor is in input "test" and user press enter-key in a simplified form like
<h:form>
<h:inputText id="test" value="#{myModel.someValue}" >
<f:ajax event="blur" execute="#this" listener="#{myBean.calculateStuff}" render="myText"/>
</h:inputText>
<h:outputText id="myText" value="#{myModel.myText}" />
<h:commandButton value="send" action="#{myBean.calculatedNextPage} ">
</h:form>
firefox invokes 1 submit, ie invokes submit and partial-request.
Is this behaviour ok? From application side it is nuisance, because there is prevention/detection for multiple request on client/server side.
We don't know the page outcome beforehand if some field's validation/conversion has failed and we might not get updated "myText" rendered on both browsers. Enter-key check to prevent from submitting is not desirable and "blur" is good in normal cases. Any suggestions how to get both browser working the same way?
This behaviour is indeed not desired. But MSIE as whole browser at its own also not. That's what you have to deal with as being a web developer. Firefox/Chrome/Safari/etc correctly skip the blur event when the submit event has occurred.
If your sole purpose is to convert/validate someValue, then you should be doing that inside a normal converter and/or validator, not inside an ajax listener method.
<h:inputText id="test" value="#{myModel.someValue}">
<f:converter converterId="someValueConverter" />
<f:validator validatorId="someValueValidator" />
<f:ajax event="blur" execute="#this" listener="#{myBean.calculateStuff}" render="myText"/>
</h:inputText>
This way you can just safely ignore "unnecessary" ajax requests.
But if you really have a hard head in, you can in your particular example always add an onsubmit handler to skip the onblur.
<h:form id="form" onsubmit="document.getElementById('form:test').onblur=null">

Resources