Dynamic ui:include updates with partial rendering don't work

UI Components for JSF
Turjakas
Posts: 48
Joined: 22 Jan 2010, 17:07

03 Feb 2010, 14:23

I'm trying to create an AJAX-based wizard-component with PrimeFaces, which would include the wizard page content dynamically using ui:include that refers to a backing bean property.
However, it seems that updates don't work correctly when using the AJAX-based p:commandLink (without update-attribute) to change the content, but the content is updated 1 request cycle late (meaning that the on the first time I click the commandLink the wizard content does not change, but on the second time it does).

I found a post explaining something that partial state saving should be disabled, but if I do that, then the results are even worse and the page layout gets corrupted completely.
The post: http://forums.java.net/jive/thread.jspa ... eID=375192

Here's the structure of the page in pseudo-JSF:

Code: Select all

<h:form>
(composite wizard component starts)

(some layout stuff inside a HTML table)

...
<ui:include src="#{cc.attrs.controller.currentStep.source}" />
...

(composite icon commandlink component)
<p:commandLink id="link" immediate="true"
                     styleClass="iconAction">
  <h:graphicImage value="#{cc.attrs.image}" styleClass="image" />
</p:commandLink>
(/composite commandlink component)

(/table)
(/composite wizard component)
</h:form>

Turjakas
Posts: 48
Joined: 22 Jan 2010, 17:07

03 Feb 2010, 15:28

I've noticed the same behavior (ui:include updates coming 1 request cycle late) even when setting ajax="false" for the p:commandLink.

Is there some kind of incompatibility with PrimeFaces and dynamic ui:include?

User avatar
Oleg
Expert Member
Posts: 3805
Joined: 02 Oct 2009, 09:41
Location: Germany, Black Forest

04 Feb 2010, 18:40

Hello,

This is my problem as well. I have really headache and didn't found a solution until now. But I know the reason of this behavior. It's not the problem from PrimeFaces (I've tried h:commandLink). This is the problem from facelets. At first I show my code

Code: Select all

<ui:composition template="/templates/twoColumnNestedLayout.xhtml">
	<ui:param name="sizeColumn" value="270"/>
	<ui:param name="minSizeColumn" value="270"/>
	<ui:param name="maxSizeColumn" value="540"/>
	<ui:define name="leftColumn">
		<h:panelGroup styleClass="ui-layout-content" layout="block">
			<p:accordionPanel activeIndex="0">
				<p:tab title="#{msgNavigation['metadata.tab.title']}">
					<h:panelGrid columns="1">
						<p:commandLink id="ptLink" value="#{msgNavigation['metadata.link.propTemplates']}"
							styleClass="#{navigationContext.sidebarSelection == 'pt' ? 'link sidebarLinkActive' : 'link sidebarLinkInactive'}"
							action="#{navigationContext.setSidebarSelection('pt')}" process="@this" update="rightColumnContent"
							async="true" onclick="selectSidebarLink(this)"/>
						<p:commandLink id="dscLink" value="#{msgNavigation['metadata.link.docStorageClasses']}"
							styleClass="#{navigationContext.sidebarSelection == 'dc' ? 'link sidebarLinkActive' : 'link sidebarLinkInactive'}"
							action="#{navigationContext.setSidebarSelection('dc')}" process="@this" update="rightColumnContent"
							async="true" onclick="selectSidebarLink(this)"/>
						<p:commandLink id="fscLink" value="#{msgNavigation['metadata.link.folderStorageClasses']}"
							styleClass="#{navigationContext.sidebarSelection == 'fc' ? 'link sidebarLinkActive' : 'link sidebarLinkInactive'}"
							action="#{navigationContext.setSidebarSelection('fc')}" process="@this" update="rightColumnContent"
							async="true" onclick="selectSidebarLink(this)"/>
					</h:panelGrid>
				</p:tab>
			</p:accordionPanel>
		</h:panelGroup>
		<h:panelGroup styleClass="sidebarSouthGroup" layout="block">
			<p:ajaxStatus onstart="showAjaxIndicator()" oncomplete="hideAjaxIndicator()"/>
			<h:graphicImage id="ajaxIndicator" library="themes" name="#{userSettings.themeName}/img/ajaxIndicator.gif" style="visibility: hidden;"/>
		</h:panelGroup>
	</ui:define>
	<ui:define name="rightColumn">
		<h:panelGroup id="rightColumnContent" layout="block">
			<ui:include src="#{navigationContext.currentSectionPath}"/>
		</h:panelGroup>
	</ui:define>
</ui:composition>
I've expected that action in p:commandLink will be called and afterwards will come a new page with <ui:include src="#{navigationContext.currentSectionPath}"/>. No. The facelets builds at first include page (ui:include gets evaluated) and then process request from commandLink. The solution is to use dynamic c:import, but it doesn't work with facelets. I will post this question in the sun forum. Maybe you already have the solution. Let me know please.

- Oleg.
PrimeFaces Cookbook (2. edition): http://ova2.github.io/primefaces-cookbook/ Learning Angular UI Development with PrimeNG: https://github.com/ova2/angular-develop ... th-primeng Blog: https://medium.com/@OlegVaraksin

User avatar
Oleg
Expert Member
Posts: 3805
Joined: 02 Oct 2009, 09:41
Location: Germany, Black Forest

04 Feb 2010, 19:58

I've debugged ui:include - it seems to be evaluated in the phase RESTORE VIEW. ui:include is just TagHandler und not a component. Therefore it's like static jsp include directive. We need dynamic include like jsp:include or c:mport. Unfortunately jsp:include / c:mport don't work with facelets.
PrimeFaces Cookbook (2. edition): http://ova2.github.io/primefaces-cookbook/ Learning Angular UI Development with PrimeNG: https://github.com/ova2/angular-develop ... th-primeng Blog: https://medium.com/@OlegVaraksin

Turjakas
Posts: 48
Joined: 22 Jan 2010, 17:07

05 Feb 2010, 15:25

Oh... this seems to be a real problem then!

The only workaround (and by workaround I do NOT mean that it is an acceptable solution) I've found is to use a regular h:link without any AJAX functionality and disable partial state saving in servlet context parameters.

Maybe someone with deeper knowledge of JSF internals, such as Cagatay, could enlighten us? :)

Would it be possible to create a real include-component that would solve the problem with the request processing phases?

User avatar
Oleg
Expert Member
Posts: 3805
Joined: 02 Oct 2009, 09:41
Location: Germany, Black Forest

05 Feb 2010, 16:01

Hi,

I' ve almost fixed this. On the page I have now an empty container element

Code: Select all

		<h:panelGroup id="rightColumnContent" layout="block">
		</h:panelGroup>
In action methods of every commandLink I construct the sub-tree for the panelGroup above. Programmatically with facelets like this one

Code: Select all

	/**
	 * Updates view section to be included.
	 */
	public void updateIncludedSection()
	{
		try {
			FacesContext facesContext = FacesContext.getCurrentInstance();
			UIViewRoot viewRoot = facesContext.getViewRoot();

			if (viewRoot instanceof PartialViewRoot) {
				viewRoot = ((PartialViewRoot) viewRoot).getBase(); /*restorePartialView(facesContext, (PartialViewRoot) viewRoot);*/
			}

			String id = "mainNavigationForm" + UINamingContainer.getSeparatorChar(facesContext) + "rightColumnContent";
			UIPanel includeSection = (UIPanel) viewRoot.findComponent(id);

			if (includeSection == null) {
				LOG.error("Component with Id '" + id + "' was not found");

				return;
			}

			FaceletFactory ff =
			    (FaceletFactory) RequestStateManager.get(facesContext, RequestStateManager.FACELET_FACTORY);
			Facelet ft = ff.getFacelet(getCurrentSectionPath());

			// construct component sub-tree with given parent
			ft.apply(facesContext, includeSection);

			// some required magic ...
			includeSection.getAttributes().remove("com.sun.facelets.MARK_ID");
		} catch (Exception ex) {
			LOG.error("Dynamic include could be not built", ex);
		}
	}
and get an exception from PrimeFacesPhaseListener :-)

Code: Select all

java.lang.NullPointerException
        at javax.faces.component.UIComponent$ComponentSystemEventListenerAdapter.processEvent(UIComponent.java:2345)
        at javax.faces.event.SystemEvent.processListener(SystemEvent.java:102)
        at com.sun.faces.application.ApplicationImpl.processListeners(ApplicationImpl.java:1993)
        at com.sun.faces.application.ApplicationImpl.invokeComponentListenersFor(ApplicationImpl.java:1941)
        at com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:285)
        at com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:243)
        at javax.faces.component.UIComponentBase.publishAfterViewEvents(UIComponentBase.java:2005)
        at javax.faces.component.UIComponentBase.doPostAddProcessing(UIComponentBase.java:1691)
        at javax.faces.component.UIComponentBase.setParent(UIComponentBase.java:403)
        at javax.faces.component.UIComponentBase$ChildrenList.add(UIComponentBase.java:2428)
        at javax.faces.component.UIComponentBase$ChildrenList.add(UIComponentBase.java:2411)
        at com.sun.faces.application.view.StateManagementStrategyImpl$4.invokeContextCallback(StateManagementStrategyImpl.java:297
)
        at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1253)
        at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:672)
        at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1262)
        at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:672)
        at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1262)
        at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:672)
        at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1262)
        at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:672)
        at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1262)
        at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:672)
        at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1262)
        at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:672)
        at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1262)
        at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:672)
        at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1262)
        at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:672)
        at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1262)
        at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:672)
        at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1262)
        at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:672)
        at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1262)
        at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:672)
        at com.sun.faces.application.view.StateManagementStrategyImpl.restoreView(StateManagementStrategyImpl.java:284)
        at com.sun.faces.application.StateManagerImpl.restoreView(StateManagerImpl.java:177)
        at com.sun.faces.application.view.ViewHandlingStrategy.restoreView(ViewHandlingStrategy.java:131)
        at com.sun.faces.application.view.FaceletViewHandlingStrategy.restoreView(FaceletViewHandlingStrategy.java:430)
        at com.sun.faces.application.view.MultiViewHandler.restoreView(MultiViewHandler.java:143)
        at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:199)
        at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
        at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:110)
        at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
        at javax.faces.webapp.FacesServlet.service(FacesServlet.java:312)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at ip.client.commons.web.secfilter.filter.SecurityFilter.doFilter(SecurityFilter.java:264)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190)
        at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92)
        at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
        at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:829)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:598)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
        at java.lang.Thread.run(Thread.java:595)
14:56:51,265 WARNING [PrimeFacesPhaseListener] Component "mainNavigationForm_rightColumnContent" not found to be updated partially
Any idea?
PrimeFaces Cookbook (2. edition): http://ova2.github.io/primefaces-cookbook/ Learning Angular UI Development with PrimeNG: https://github.com/ova2/angular-develop ... th-primeng Blog: https://medium.com/@OlegVaraksin

User avatar
Oleg
Expert Member
Posts: 3805
Joined: 02 Oct 2009, 09:41
Location: Germany, Black Forest

05 Feb 2010, 17:12

Hi,

This was a temporary log output. It's working now! You can add facelets programmatically how I mentioned above. These articles was helpful for me http://confluence.highsource.org/displa ... f+Facelets
http://forums.java.net/jive/thread.jspa ... 0&tstart=0

A question to Cagatay. I've detected an undocumented thing. Your PostRestoreViewHandler set an PartialViewRoot and your PrimeFacesPhaseListener restore the original view again. Well. But I didn't know that and after detection of this behavior I had to do

Code: Select all

			if (viewRoot instanceof PartialViewRoot) {
				viewRoot = ((PartialViewRoot) viewRoot).getBase();
			}
because if you call findComponent(id) somewhere between first and last lifecycle phase with component id outside of PartialViewRoot (but still in entire ViewRoot) the component will be not found. I think, PartialViewRoot should overwrite the method findComponent.

The problem is now solved.
- Oleg.

P.S. By the way, I've tested preRenderViewEvent with some PrimeFaces / and not PrimeFaces components and it didn't work...
<f:event type="javax.faces.event.PreRenderViewEvent" listener="#{someBean.preRenderView}"/>.
PrimeFaces Cookbook (2. edition): http://ova2.github.io/primefaces-cookbook/ Learning Angular UI Development with PrimeNG: https://github.com/ova2/angular-develop ... th-primeng Blog: https://medium.com/@OlegVaraksin

Turjakas
Posts: 48
Joined: 22 Jan 2010, 17:07

08 Feb 2010, 18:08

Oleg,

Great to see some progress on this, but what you are doing looks more like hacking and working around PrimeFaces and the JSF implementation, which is not good in my opinion as it introduces dependencies on the underlying implementation.

I'd really like to see some other kind of solution on how to implement dynamic includes.

User avatar
Oleg
Expert Member
Posts: 3805
Joined: 02 Oct 2009, 09:41
Location: Germany, Black Forest

09 Feb 2010, 11:43

Hello,

There isn't other kind of solution by reason of ui:include nature :-) ui:include is not a component and is evaluated quite early in the RESTORE VIEW phase. JSF with facelets miss really dinamic includes.

My solution works great, but you should be care with IDs in your facelets. Set them by hand manually because PrimeFaces PostRestoreViewHandler store this information. If you let generate IDs automatically, then they can be different from generated by facelets' apply method in the INVOKE APPLICATION phase (see my code).

Best regards.
PrimeFaces Cookbook (2. edition): http://ova2.github.io/primefaces-cookbook/ Learning Angular UI Development with PrimeNG: https://github.com/ova2/angular-develop ... th-primeng Blog: https://medium.com/@OlegVaraksin

Turjakas
Posts: 48
Joined: 22 Jan 2010, 17:07

09 Feb 2010, 16:08

Oleg,

I tried your approach, but I'm still running into problems.

With partial state saving disabled the page does render, but every other time it gets rendered without proper CSS styles and every other time it renders fine.
And the page still renders one request cycle late.

Also, I get errors about duplicate IDs and using f:subview as a container for the included page instead of the h:panelGroup does not seem to help.

When partial state saving is enabled I get a NullPointerException.

Do you have everything working properly and can you do AJAX requests which update the included page?

Post Reply

Return to “PrimeFaces”

  • Information
  • Who is online

    Users browsing this forum: Google [Bot] and 29 guests