ui:repeat + AJAX - ajax

We have a list to be displayed under a panel of the screen where all the code in which the fields are repeatable are kept under a different Facelet file. While I am trying to render an image based on the listener's action for an ajax event I am getting some problem to update the image with ID as JSF is generating an ID with the index in the middle due to the use of <ui:repeat> like so repeatForm:repeat:2:redimage.
This is the main page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
<title>Repeat Test Demo</title>
</h:head>
<h:body>
<h:form id="repeatForm">
<ui:repeat id ="repeat" value="#{listBean.xyzList}" var="repeatListVar">
<p:panel id="genLiabPanelRender">
<ui:include src="MyScreen.xhtml" />
</p:panel>
</ui:repeat>
</h:form>
</h:body>
</html>
This Facelet is repeatable based on the list size within the panel.
MyScreen.xhtml this is the include Facelet file:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.prime.com.tr/ui">
<h:body class="body">
<h:panelGrid columns="4" border="0" width="90%">
<h:panelGroup style="display:block;text-align:left;width: 320px">
<h:selectBooleanCheckbox value="#{repeatListVar.primaryPolicyInd}" />
<h:outputText value="#{label.primaryCov}" />
</h:panelGroup>
<h:panelGroup style="display:block;text-align:left;width: 240px">
<h:selectBooleanCheckbox value="#{repeatListVar.abcInd1}" />
<h:outputText value="#{label.commGenLiab}" />
</h:panelGroup>
<h:panelGroup style="display:block;text-align:left;width: 180px">
<h:outputText value=" #{label.eachOccur}" style="text-align:left" />
</h:panelGroup>
<h:panelGroup style="display:block;text-align:left;width: 130px">
<p:inputMask mask="#{label.limitAmtMask}" id="genLiabEachOccAmt"
value="#{repeatListVar.a25GLEOAmt}" required="true"
style="width: 90px">
<f:ajax event="blur" render="redimage" listener="#{repeatListVar.testA25GLEOAmt}"/>
</p:inputMask>
<h:graphicImage id="redimage" url="/images/icons/redIcon.png" rendered="#{repeatListVar.testA25GLEOAmtInd}" />
</h:panelGroup>
This ends up generating IDs for the <h:outputText> that look like: repeatForm:repeat:2:redimage. But because we're using the <f:ajax> tag, we only need to specify "redimage". The tag takes care of the work of finding out what the real ID is.
We are calling a method in the listener and set the value of boolean indicator to either true or false which is false by default. The indicator is used to render the image.
But when we are using this <f:ajax> to render the image based on the indicator value, I am getting the error
malformedXML: During update repeatForm:repeat:2:redimage not found
How is this caused and how can I solve this?

This should work. I see only 2 possible causes:
Your bean is request scoped and does not preserve the <ui:repeat> value. Fix the bean constructor's job and/or put the bean in the view scope.
Your HTML output is syntactically invalid and is therefore confusing the JavaScript code who is responsible for updating the HTML DOM tree. You should not use <html> and <h:body> in the include file. It would be duplicated in the HTML output. You should only use it in the master page. The include page should look like this:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:panelGrid columns="4" border="0" width="90%">
...
</h:panelGrid>
</ui:composition>
Do not duplicate <html>, <h:head> and/or <h:body> in there.

Related

Trigger <cc:clientBehavior> event from <p:ajax> nested in composite

Is there any way to trigger an event in my composite component with clientBehavior and jQuery?
If not possible, what is the proper way to create custom events in composites?
Example:
ajaxTest.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:p="http://primefaces.org/ui">
<cc:interface>
<cc:clientBehavior name="myEvent" targets="myLabel" event="myEvent"/>
</cc:interface>
<cc:implementation>
<div id="#{cc.clientId}">
<p:outputLabel id="myLabel" value="Test label" />
<p:commandLink value="trigger event"
onstart="$(PrimeFaces.escapeClientId('#{cc.clientId}:myLabel')).trigger('myEvent');"/>
</div>
</cc:implementation>
</html>
testPage.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:demo="http://xmlns.jcp.org/jsf/composite/component">
<h:body>
<h:form id="form-1">
<demo:ajaxTest>
<p:ajax event="myEvent" oncomplete="alert('Ajax called');" />
</demo:ajaxTest>
</h:form>
</h:body>
</html>
The <cc:clientBehavior event> must declare a valid event name as supported by the target component in question. In this context, it must thus be exactly the same event name as you would use when nesting <p:ajax> directly inside <p:commandLink>. You perhaps want action or click.
<cc:clientBehavior ... event="action" />
See also:
What values can I pass to the event attribute of the f:ajax tag?

Include xhtml page with ajax request in multi-level page template (JSF, Primefaces)

I am trying to create an application using JSF and Primefaces. Unfortunately, I have an issue about page templates and could not manage to work it out properly.
I have a page template like this. What I want is to load Left Menu and the Content with ajax request without loading whole page. However, when I click the page2 link, everything gets broken like this.
I tried different combinations of how to place form, include, composition tags but, it's still the same. Only change is my server response according to place of form tag. When I checked the response it seems alright. It does not try to load whole page and nothing seems wrong to me:
<?xml version='1.0' encoding='UTF-8'?>
<partial-response id="j_id1"><changes><update id="javax.faces.ViewRoot"><![CDATA[<script id="innerLayout_s" type="text/javascript">$(function(){PrimeFaces.cw( "Layout","widget_innerLayout",{id:"innerLayout",widgetVar:"widget_innerLayout",west:{paneSelector:'#left',size:"200",resizable:false,closable:false},center:{paneSelector:'#innerContent',size:"auto",resizable:false,closable:false}},"layout");}) ;</script><div id="innerLayout"><div id="left" class="ui-layout-unit ui-widget ui-widget-content ui-corner-all ui-layout-west"><div class="ui-layout-unit-header ui-widget-header ui-corner-all"><span class="ui-layout-unit-header-title">Left Menu</span></div><div class="ui-layout-unit-content ui-widget-content">
<form id="leftForm" name="leftForm" method="post" action="/Magician/pages/page2.xhtml" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="leftForm" value="leftForm" />
Page2 Left Menu
</form></div></div><div id="innerContent" class="ui-layout-unit ui-widget ui-widget-content ui-corner-all ui-layout-center"><div class="ui-layout-unit-content ui-widget-content">
<form id="contentForm" name="contentForm" method="post" action="/Magician/pages/page2.xhtml" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="contentForm" value="contentForm" />
Page2 Content
</form></div></div></div>]]></update><update id="j_id1:javax.faces.ViewState:0"><![CDATA[2499963408064928377:-8018685353649439725]]></update></changes></partial-response>
However, when I look the console, there is an error like below:
Uncaught TypeError: Cannot read property '0' of null primefaces.js.xhtml?ln=primefaces&v=5.0:2
PrimeFaces.ajax.Utils.updateElement primefaces.js.xhtml?ln=primefaces&v=5.0:2
PrimeFaces.ajax.ResponseProcessor.doUpdate primefaces.js.xhtml?ln=primefaces&v=5.0:2
PrimeFaces.ajax.Response.handle primefaces.js.xhtml?ln=primefaces&v=5.0:2
p.success primefaces.js.xhtml?ln=primefaces&v=5.0:2
i jquery.js.xhtml?ln=primefaces&v=5.0:25
cd.fireWith jquery.js.xhtml?ln=primefaces&v=5.0:25
cg jquery.js.xhtml?ln=primefaces&v=5.0:25
i
Here are my codes:
default.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>My Application</title>
</h:head>
<h:body>
<h:outputStylesheet name="css/style.css" />
<p:layout id="fullPageLayout" fullPage="true">
<p:layoutUnit id="header" position="north" size="80">
<h:form id="headerForm">
<ui:insert name="headerUI">
<ui:include src="header.xhtml" />
</ui:insert>
</h:form>
</p:layoutUnit>
<p:layoutUnit id="content" position="center">
<ui:insert name="contentUI" />
</p:layoutUnit>
</p:layout>
</h:body>
</html>
header.xhtml:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<p:tabMenu id="tabMenu" activeIndex="#{templateBean.activeIndex}">
<p:menuitem value="page1" action="#{templateBean.navigateToPage(0)}" update=":contentForm,tabMenu" />
<p:menuitem value="page2" action="#{templateBean.navigateToPage(1)}" update=":contentForm,tabMenu" />
</p:tabMenu>
</ui:composition>
content.xhtml:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<p:layout id="innerLayout">
<p:layoutUnit id="left" position="west" size="200" header="Left Menu">
<h:form id="leftForm">
<ui:insert name="leftUI" />
</h:form>
</p:layoutUnit>
<p:layoutUnit id="innerContent" position="center">
<h:form id="contentForm">
<ui:insert name="centerUI" />
</h:form>
</p:layoutUnit>
</p:layout>
</ui:composition>
index.xhtml:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
template="templates/default.xhtml">
<ui:define name="contentUI">
<ui:include src="#{templateBean.activePage}.xhtml" />
</ui:define>
</ui:composition>
page1.xhtml:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
template="templates/content.xhtml">
<ui:define name="leftUI">
<h:outputText value="Page1 Left Menu" />
</ui:define>
<ui:define name="centerUI">
<h:outputText value="Page1 Content" />
</ui:define>
</ui:composition>
page2.xhtml:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
template="templates/content.xhtml">
<ui:define name="leftUI">
<h:outputText value="Page2 Left Menu" />
</ui:define>
<ui:define name="centerUI">
<h:outputText value="Page2 Content" />
</ui:define>
</ui:composition>
TemplateBean.java:
package com.myapplication.pagebeans;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
#Component
#Scope("request")
public class TemplateBean {
private int activeIndex;
private String activePage = "page1";
public String navigateToPage(int index) {
activeIndex = index;
switch (index) {
case 0:
activePage = "page1";
break;
case 1:
activePage = "page2";
break;
default:
break;
}
return activePage;
}
public int getActiveIndex() {
return activeIndex;
}
public String getActivePage() {
return activePage;
}
}
Sorry for the long question and images (site does not let me to load images because of my reputation) but, I tried give information as much as I can.
Thanks in advance.
I searched a lot and already look at different questions like below ones:
How to include common content into multiple level template page
How to include another XHTML in XHTML using JSF 2.0 Facelets?
Facelets multi-level templates - ui:define not rendered
PrimeFaces exension javascript error

Composite Component Binding is resolves to null

I am trying to bind a composite component to an ajax listener but the bind variable resolves to null. If I use the bind variable as part of the body, eg. #{bind} it does resolve properly. I assume it is a bug, but would like a second opinion before I report it. Thanks
page:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:composite="http://xmlns.jcp.org/jsf/composite"
xmlns:jstl="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:jfunc="http://xmlns.jcp.org/jsp/jstl/functions"
xmlns:jid1="http://mydomain.com/facelets">
<h:head></h:head>
<h:body>
<h:form id="commentBoxForm">
<jid1:confirmModal title="t" cssID="a" binding="#{bind}">
</jid1:confirmModal>
<h:commandLink value="click">
<f:ajax execute="#this" render="#form"
listener="#{bind.getFamily()}" />
</h:commandLink>
</h:form>
</h:body>
</html>
component:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:composite="http://xmlns.jcp.org/jsf/composite"
xmlns:jstl="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:jfunc="http://xmlns.jcp.org/jsp/jstl/functions"
xmlns:jid1="http://mydomain.com/facelets">
<composite:interface>
<composite:attribute name="cssID" required="true" />
<composite:attribute name="title" required="true" />
</composite:interface>
<composite:implementation>
<h:panelGroup >
......
</h:panelGroup>
</composite:implementation>
</ui:composition>
This is a bug. See here for details.
A composite component binding attribute will not work properly for Ajax calls.

Primefaces command button action is not called for the second time

I have spring integrated with JSF and I am facing a strange behavior:
I hit the command button the action method in the managed bean is hit successfully (I removed it in the below example).
The Ajax update works perfect and the form is updated.
I hit another button the action method now in the managed bean isn't hit.
The panel is restored to the initial view and it freezes on this view.
I can't get the form updated except if I refresh the page and these steps are repeated.
DealerInfo.xhtml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<ui:composition template="/WEB-INF/templates/default.xhtml">
<ui:define name="content">
<h:form id="toolBarForm">
<p:toolbar style="margin-bottom:5px;">
<p:toolbarGroup align="right">
<p:commandButton value="Add"
update=":toolBarForm" icon="ui-icon-plusthick" />
</p:toolbarGroup>
</p:toolbar>
<p:messages id="dealerInfoMessages" />
<ui:include src="/pages/dealers/DealerMainInfo.xhtml" />
</h:form>
</ui:define>
</ui:composition>
</html>
pages/dealers/DealerMainInfo.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<ui:composition>
<p:panel id="dealerMainInfoPanel" header="Dealer Main Info"
style="margin-bottom:5px;">
<h:panelGrid columns="2">
<p:outputLabel for="dealerCode" value="Dealer Code" />
<p:inputText id="dealerCode" required="true"
value="#{dealerMainInfoBO.dealerCode}" style="width:200px;" />
<p:outputLabel for="dealerName" value="Dealer Name" />
<p:inputText id="dealerName" required="true"
value="#{dealerMainInfoBO.dealerName}" style="width:200px;" />
</h:panelGrid>
</p:panel>
</ui:composition>
</html>
Update:
I created a very simple single page and I noticed that when I remove the <h:head></h:head> tags the ajax works like a charm BUT without the fancy primefaces UI, and when I add the tags the ajax stop (this is normal cause <h:head></h:head> tags fetch all the needed JSs and CSSs), What Can I Do?
Example.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<f:view contentType="text/html">
<h:head>
</h:head>
<h:body>
<h:form id="toolBarForm">
<p:toolbar style="margin-bottom:5px;">
<p:toolbarGroup align="right">
<p:commandButton value="Add" update=":toolBarForm"
action="#{bean.add}" />
</p:toolbarGroup>
</p:toolbar>
<p:messages id="operationDefinitionMessages" />
<h:panelGrid columns="2">
<p:outputLabel for="text" value="Text" />
<p:inputText id="text" required="true" value="#{bean.text}" />
</h:panelGrid>
</h:form>
</h:body>
</f:view>
</html>
My Environment
Primefaces:3.5
JSF-Mojarra:2.2
Spring:3.2.3.RELEASE
In case anyone faces the same issue. I noticed that the Primefaces showcase is using JSF-Mojarra-2.1.22. I downgraded my JSF-Mojarra version from 2.2 to 2.1.22 and it worked like a charm.
If I am not wrong, I guess it should be reported to primefaces (if it isn't a current issue).

Error: <f:ajax> contains an unknown id when used with composite:insertChildren

I defined a composite component (actually a few) and when I try to re-render a component inserted with I get the error mentioned:
<f:ajax> contains an unknown id ':contentFrm' - cannot locate it in the context of the component j_idt40
If I simply replace:
<et:pageContent formId="contentFrm">
with
<h:form id="contentFrm">
<div>
then everything works fine
Here is the relevant code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
<composite:attribute name="styleClass" default="access-box-content alpha omega grid-12" />
<composite:attribute name="formId" default="#{cc.attrs.id}" />
</composite:interface>
<composite:implementation>
<h:form id="#{cc.attrs.formId}">
<div class="#{cc.attrs.styleClass}">
<composite:insertChildren/>
</div>
</h:form>
</composite:implementation>
</html>
This is how I use the composite
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition id="landing" xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:et="http://java.sun.com/jsf/composite/components"
template="/layout/template.xhtml"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<ui:define name="main-content">
<et:pageTitle title="#{msg.trx_lastTrx}" />
<et:tabBar formId="currentTrxFrm">
<et:tab bean="#{accountTransactionBacking}"
prompt="#{msg.trx_currentTrxs}"
reRender=":contentFrm"
tabId="1"
active="true"/>
</et:tabBar>
<et:pageContent formId="contentFrm">
<et:tabContentPanel rendered="#{accountTransactionBacking.selectedTab ==1}">
<ui:include src="/app/summary/currentTrxRG.xhtml" rendered="#{accountTransactionBacking.selectedTab ==1}"/>
</et:tabContentPanel>
</et:pageContent>
</ui:define>
</ui:composition>
TIA
Some more tests.. using same component get's the same result.. for example the following code gives similar error (even replacing render="accountSummaryLines" with render=":accountSummaryLines")..
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition id="landing" xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:et="http://java.sun.com/jsf/composite/components"
template="/layout/template.xhtml"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<ui:define name="main-content">
<et:pageTitle title="#{msg.ls_lastStatement}" />
<et:tabBar formId="acctSummTabFrm">
<et:tab/>
</et:tabBar>
<et:pageContent formId="accountButtonsFrm">
....
<et:div styleClass="accountSummaryLines" divId="lastStatementLines">
<ui:repeat var="row" value="#{lastStatementBacking.lines.data}">
<h:outputText escape="false" value="#{row}" styleClass="grid-12 lastStatementDetail"/><br></br>
</ui:repeat>
</et:div>
<et:div styleClass="access-box-footer">
<h:commandButton styleClass="left" action="#{lastStatementBacking.lines.prevPage}" value="#{msg.buttonPrevPage}" style="float:left;">
<f:ajax render="accountSummaryLines" />
</h:commandButton>
<h:commandButton styleClass="right" action="#{lastStatementBacking.lines.nextPage}" value="#{msg.buttonNextPage}">
<f:ajax render="accountSummaryLines" />
</h:commandButton>
</et:div>
</et:pageContent>
</ui:define>
</ui:composition>
The only way I got this particular example working is using render="#form" like so..
It cannot be found because the composite component is by itself a NamingContainer. The real valid client ID would be :idOfComposite:contentFrm where idOfComposite is the (auto)generated ID of the composite component itself. If you do a View Source in webbrowser and locate the <form> in question, then you'll see it.
You need to give the composite component a fixed ID
<et:pageContent id="contentFrm">
and use exactly this ID on a plain HTML element which wraps the composite's content, e.g. <div> or <span>.
<composite:implementation>
<div id="#{cc.id}">
<h:form>
<div class="#{cc.attrs.styleClass}">
<composite:insertChildren/>
</div>
</h:form>
</div>
</composite:implementation>

Resources