I use JSF 2.0 (Apache myFaces) on WebSphere Application Server 8.
I have a bean which contains a list of charts (data for jquery HighCharts).
For each chart I need some JSF components + one Highchart Wrapper written as CompositeCompoent (look here)
So I use the ui:repeat function of jsf 2 like this:
<?xml version="1.0" encoding="UTF-8" ?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:hc="http://java.sun.com/jsf/composite/chartComponents"
template="/template/mytemplate.xhtml">
<ui:define name="content">
<ui:repeat value="#{chartCtrl.charts }" var="chart" id="chartrepeat" varStatus="chartStatus">
#{chartStatus.index }
<h:form id="chartform_#{chartStatus.index }">
<!-- some jsf select stuff-->
</h:form>
#{chartStatus.index }
<hc:Chart title="Statistics" id="hcchart_#{chartStatus.index }"
<!-- here's the problem-->
<ui:repeat value="#{chart.series }" var="serie">
<hc:ChartSeries series="#{serie.data }" />
</ui:repeat>
</hc:Chart>
#{chartStatus.index }
</p:panel>
</ui:repeat>
<h:outputScript library="js" name="highcharts.js" />
<h:outputScript library="js/modules" name="exporting.js" />
<h:outputScript library="js" name="jquery-1.9.1.min.js" target="head" />
</ui:define>
</ui:composition>
The #{chartStatus.index } works every where but not in hc:Chart id="".
The generated js and div by this CC contains the id 'hcchart_chartdiv'. The index of the current repeat left.
How can I pass the correct number to the id attribute?
EDIT: Composite Component
Here is a part of the hc:Chart where the ID should be used
<cc:implementation>
<div id="#{cc.id}_chartDiv" />
<!-- Highcharts -_>
<script type="text/javascript">
$(function() {
// Data must be defined WITHIN the function. This prevents
// different charts using the same data variables.
var options = {
credits : {
enabled : false
},
chart : {
renderTo : '#{cc.id}_chartDiv',
....
</script>
When I leave the attribute id in hc:Chart empty, then the generated ID is something like "j_id568185923_1_5f9521d0_chartDiv". But still without :row:.
EDIT 2: IndexOf Approach
I tested another approach to set the ID of my chart.
id="hc_#{chartCtrl.charts.indexOf(chart) }"
I tried to use the IndexOf method of my ArrayList. I implemented HashCode und Equals method in all Classes. When I test it, it works fine.
But when I use it with EL I get -1 returned.
Solution
Just as BalusC said I cant use the ID tag for EL. So I simple created a new attribute in my CC. That works fine (just so easy).
Thanks BalusC.
Does someone has another idea?
The id attribute is evaluated during view build time. The <ui:repeat varStatus> is set during view render time which is after view build time. Essentially, you've the same problem as explained in detail here: JSTL in JSF2 Facelets... makes sense?
Any EL expression in the id attribute must be available during view build time. If you replace <ui:repeat> by <c:forEach> which runs during view build time, then the id must be properly set. An alternative is to just get rid of EL in those id attributes based on <ui:repeat varStatus>. JSF will already automatically suffix the IDs of <ui:repeat> child components with the row index.
Note that the <c:forEach> may have unforeseen side effects when used in combination with view scoped beans and partial state saving enabled. See the aforelinked answer for details.
Related
I use flash scope to pass a setting object between #viewscoped contollers. But if I make a page reload on one of them, then the flash map is empty and the setting object is not initialized. Is it possible to keep flash scope on page reload?
My source code to store/retrieve settings:
FistPage.xhtml
...
<p:commandButton value="next"
action="#{firstPageController.transferConfig}"
process="#this" />
...
FirstPageController.java
#ManagedBean(name = "firstPageController")
#ViewScoped
public class FirstPageController {
...
public String transferConfig() {
FacesContext.getCurrentInstance().getExternalContext().getFlash().put("searchConfig", searchConfig);
return "/secondPage.xhtml?faces-redirect=true";
}
...
}
SecondPage.xhtml
...
<h:outputLabel value="value">
<f:event type="preRenderComponent" listener="#{secondPageController.onPageLoad()}"/>
</h:outputLabel>
...
SecondPageController.java
#ManagedBean(name = "secondPageController")
#ViewScoped
public class SecondPageController {
...
public void onPageLoad()
{
flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
searchConfig = ((SearchFilterConfig) flash.get("searchConfig"));
flash.putNow("searchConfig", searchConfig);
flash.keep("searchConfig");
}
...
}
I use Mojarra 2.1.29
Thanks
I just did some tests in my playground project and realized it's actually possible to keep the state of the flash parameters even if you GET the page again, using {flash.keep}. That's how the JSF docs explain it:
The implementation must ensure the proper behaviour of the flash is preserved even in the case of a <navigation-case> that contains a <redirect />. The implementation must ensure the proper behavior of the flash is preserved even in the case of adjacent GET requests on the same session. This allows Faces applications to fully utilize the Post/Redirect/Get design pattern.
Here you've got a nice basic test case:
page1.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head />
<h:body>
<h:form>
<h:button id="nextButton" value="Next (button)" outcome="page2.xhtml" />
<c:set target="#{flash}" property="foo" value="bar" />
</h:form>
</h:body>
</html>
page2.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<head />
<body>foo = #{flash.keep.foo}
</body>
</html>
Just open the first page and click on the button which will redirect you to the second one. Then refresh the second page as many times as you want and you'll find the parameter persisting.
Tested in Mojarra 2.2.6
I want to set a ui:param depending on a bean value and I thought using c:if was a good idea. So I put in my page the following code:
<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:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:wai="http://www.id.ethz.ch/wai/jsf"
template="/view/listView.xhtml">
<c:if test="#{subscriptionListController.model.listViewName eq 'mySubscriptions'}">
<ui:param name="title" value="#{msg.subscriptionTitleMySubscriptions}"/>
</c:if>
<c:if test="#{subscriptionListController.model.listViewName eq 'paidSubscriptions'}">
<ui:param name="title" value="#{msg.subscriptionTitlePaidSubscriptions}"/>
</c:if>
<c:if test="#{subscriptionListController.model.listViewName eq 'allSubscriptions'}">
<ui:param name="title" value="#{msg.subscriptionTitleAllSubscriptions}"/>
</c:if>
....
but the parameter is not set...
If I let print out the value of #{subscriptionListController.model.listViewName eq 'mySubscriptions'} I get true in the corresponding case and false in the other two cases.
At the beginning I had only 2 possibilities and solved it with the ternary operator:
<ui:param name="title" value="#{subscriptionListController.model.listViewName eq 'mySubscriptions' ? msg.subscriptionTitleMySubscriptions : msg.subscriptionTitlePaidSubscriptions}"/>
and it worked. But now I have more possibilities...
What am I doing wrong?
As indicated by <ui:composition template>, this page represents a template client.
Any <ui:param> outside <ui:define> applies to the master template (the file which you declared in template attribute) and is ignored inside the template client itself. If you intend to prepare variables for inside the template client, you should put <ui:param> inside <ui:define>.
But there's another thing: the original purpose of <ui:param> is to pass variables to the file referenced by <ui:composition template>, <ui:decorate template> or <ui:include src>, not to prepare/set variables inside the current facelet context. For the sole functional requirement of preparing/setting variables in the current EL context, you'd better be using JSTL <c:set> for the job. You can use <ui:param> for this, but this isn't its original intent and didn't work that way in older MyFaces versions.
Thus, so:
<ui:define>
<c:if test="#{subscriptionListController.model.listViewName eq 'mySubscriptions'}">
<c:set var="title" value="#{msg.subscriptionTitleMySubscriptions}"/>
</c:if>
<c:if test="#{subscriptionListController.model.listViewName eq 'paidSubscriptions'}">
<c:set var="title" value="#{msg.subscriptionTitlePaidSubscriptions}"/>
</c:if>
<c:if test="#{subscriptionListController.model.listViewName eq 'allSubscriptions'}">
<c:set var="title" value="#{msg.subscriptionTitleAllSubscriptions}"/>
</c:if>
...
</ui:define>
Unrelated to the concrete problem, you can optimize this as follows without the need for an unmaintainable <c:if> group which would only grow with every subscription type:
<ui:define>
<c:set var="subscriptionTitleKey" value="subscriptionTitle.#{subscriptionListController.model.listViewName}">
<c:set var="title" value="#{msg[subscriptionTitleKey]}"/>
...
</ui:define>
with those keys
subscriptionTitle.mySubscriptions = Title for my subscriptions
subscriptionTitle.paidSubscriptions = Title for paid subscriptions
subscriptionTitle.allSubscriptions = Title for all subscriptions
You are using JSTL with Facelets. JSTL are executed during view build time, and not in render phase. Additionally there some issues with processing them in JSF2 libraries - like in older Mojarra versions, where they didn't work on view scoped beans with partial state saving - see https://stackoverflow.com/a/3343681). This is why your EL expression has worked.
The solution is to avoid JSTL - use ui:repeat instead c:forEach and EL expression and conditional rendering instead of c:if.
I want to invoke one method through a link from Facelets:
My Facelets code is like:
<h:commandButton value="A" actionListener="#{customerData.searchedCustomerListA}" />
<h:commandLink value="A" actionListener="#{customerData.searchedCustomerListA}"/>
Backing bean code is like:
public void searchedCustomerListA(ActionEvent ae){
customerName = "A";
leftCustomerListAvailable.clear();
if(customerDataBean.getSearchedCustomerList(customerName)!= null)
leftCustomerListAvailable =customerDataBean.getSearchedCustomerList("A");
}
The same code is working for <h:commandButton> but not working for <h:commandLink>. How is this caused and how can I solve it?
The technical difference between <h:commandLink> and <h:commandButton> is that the link uses JavaScript to submit the parent form. So if it doesn't work while a syntactically equivalent button works fine, then that can only mean that either JavaScript is disabled in browser, or that the jsf.js file containing the mandatory helper functions isn't included in the page (which you should easily have noticed by seeing JS errors in the JS console of browser's builtin developer toolset).
So, to fix this problem, you need to verify if JS is enabled in browser and that you've a <h:head> component instead of plain HTML <head> in the template, so that JSF will be able to auto-include the jsf.js file.
Or, if your application's business requirements requires that the application functions as designed with JS disabled, then you should stick to <h:commandButton> and throw in some CSS to make it to look like a link (e.g. remove background, padding, border, inset, etc).
Try this, This sould work.
<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">
<h:form>
<h:commandLink type="button" action="#{testBean.tsetLink}">
<h:outputText value="A" />
</h:commandLink>
</h:form>
</html>
ManagedBean
#ManagedBean
#RequestScoped
public class TestBean {
public void tsetLink(){
System.out.println("Link clicked!!!!!!!!!!!!");
}
}
I my case the cause of this issue was a poorly configured url rewriting filter. One of the filters patterns unintentionally matched http://localhost:8080/mysite/javax.faces.resource/jsf.js.xhtml?ln=javax.faces which prevented jsf.js from being loaded. Check this answer: Clicking h:commandLink causes Uncaught ReferenceError: mojarra is not defined.
I have an issue with using p:outputLabel when used with composite component. I have composite component with p:inputText field (I removed irrelevant parts from component):
<cc:interface>
<cc:editableValueHolder name="myInput" targets="myInput"/>
<cc:attribute name="required" required="true" type="java.lang.Boolean" default="false"/>
</cc:interface>
<cc:implementation>
<p:inputText id="myInput" required="#{cc.attrs.required}"/>
</cc:implementation>
Now, I wont to use this component with p:outputLabel:
<p:outputLabel for="myComponent:myInput" value="#{resources['myLabel']}:"/>
<my:myComponent id="myComponent" required="#{myBean.required}"/>
Everything works fine, required validation, message is displayed as well, but there is no * sign on label, as there is when I connect label directly to p:inputText component. If I, on the other hand, hardcode required="true" on p:inputText everything works fine.
I debugged through org.primefaces.component.outputlabel.OutputLabelRenderer and discovered that component is recognized as UIInput, but input.isRequired() returns false. Farther debugging discovered that required attribute isn't yet defined on component, so it returns false as default value i UIInput:
(Boolean) getStateHelper().eval(PropertyKeys.required, false);
Also, if I just move p:outputLabel inside composite component everything works fine. Like EL is evaluated later inside composite component?
I'm using Primefaces 3.5 with Mojarra 2.1.14
This is, unfortunately, "by design". The evaluation of the #{} expressions is deferred to the exact moment of the access-time. They're unlike "standard" EL ${} in JSP not evaluated at the exact moment they're been parsed by the tag handler and "cached" for future access during the same request/view. At the moment the <p:outputLabel> is rendered, and thus the #{cc.attrs.required} as referenced by UIInput#isRequired() needs to be evaluated, there's no means of any #{cc} in the EL context. So any of its attributes would not evaluate to anything. Only when you're sitting inside the <cc:implementation>, the #{cc} is available in the EL context and all of its attribues would thus successfully evaluate.
Technically, this is an unfortunate corner case oversight in the design of <p:outputLabel>. Standard JSF and EL are namely behaving as specified. Basically, the presentation of the label's asterisk depending on the input's required attribute should be evaluated the other way round: at the moment the <p:inputText> inside the composite is to be rendered or perhaps even already when it's to be built. Thus, the label component should not ask the input component if it's required, but the input component should somehow notify the label component that it's required. This is in turn hard and clumsy (and thus inefficient) to implement.
If moving the label to inside the composite is not an option, then your best bet is to create a tag file instead of a composite component around the input component. It only requires some additional XML boilerplate.
/WEB-INF/tags/input.xhtml:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui"
>
<c:set var="id" value="#{not empty id ? id : 'myInput'}" />
<c:set var="required" value="#{not empty required and required}" />
<p:inputText id="#{id}" required="#{required}"/>
</ui:composition>
/WEB-INF/my.taglib.xml:
<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
version="2.0"
>
<namespace>http://example.com/my</namespace>
<tag>
<tag-name>input</tag-name>
<source>tags/input.xhtml</source>
</tag>
</facelet-taglib>
/WEB-INF/web.xml:
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/my.taglib.xml</param-value>
</context-param>
Usage:
<html ... xmlns:my="http://example.com/my">
...
<p:outputLabel for="myInput" value="#{resources['myLabel']}:" />
<my:input id="myInput" required="#{myBean.required}" />
I just did a quick test and it works fine for me.
See also:
When to use <ui:include>, tag files, composite components and/or custom components?
I have a template and in its Definition I use several forms and buttons.
The problem is the definition (define) xhtml file does not know the component hierarchy.
And for example I want to update the element "table2" in a different form in the same define file.
Template Insert:
<p:tabView id="nav"> <!-- nav -->
<ui:insert name="content_nav">content navigation</ui:insert>
</p:tabView>
defines the first level of my hierarchy "nav"
Template define:
<ui:define name="content_nav">
<h:form id="form1"> <!-- nav:form1 -->
<h:dataTable id="table1"/> <!-- nav:form1:table1 -->
<p:inputText value="#{bean.value}"/>
<p:commandButton action="..." update="nav:form2:table2"/>
</h:form>
<h:form id="form2">
<h:dataTable id="table2"/> <!-- nav:form2:table2 -->
<!-- other elements -->
</h:form>
</ui:define>
In my define part I don't want to know "nav"!
How can I do this? or how can I move one naming component upwards?, or save the highest parent complete id in a variable?
sometimes i saw something like:
update=":table2"
But I could not find any informations about this?, the JavaEE 6 documentation just mentions the # keywords.
Ugly, but this should work out for you:
<p:commandButton action="..." update=":#{component.namingContainer.parent.namingContainer.clientId}:form2:table2" />
As you're already using PrimeFaces, an alternative is to use #{p:component(componentId)}, this helper function scans the entire view root for a component with the given ID and then returns its client ID:
<p:commandButton action="..." update=":#{p:component('table2')}" />
ugly answer works well
update=":#{component.namingContainer.parent.namingContainer.clientId}:form2:table2
mainly more useful updating from opened dialog to parent datatable
You may use binding attribute to declare EL variable bound to JSF component. Then you may access absolute client id of this component by using javax.faces.component.UIComponent.getClientId(). See example below:
<t:selectOneRadio
id="yourId"
layout="spread"
value="#{yourBean.value}"
binding="#{yourIdComponent}">
<f:selectItems value="#{someBean.values}" />
</t:selectOneRadio>
<h:outputText>
<t:radio for=":#{yourIdComponent.clientId}" index="0" />
</h:outputText>
Try this:
<h:commandButton value="Click me">
<f:ajax event="click" render="table" />
</h:commandButton>
Additionally to the solutions above I had the problem, that I had to dynamically generate the to-be-updated components (many) based on server-side logic (with maybe harder to find out nesting).
So the solution on the server-side is an equivalent to update=":#{p:component('table2')}"1 which uses org.primefaces.util.ComponentUtils.findComponentClientId( String designId ):
// UiPnlSubId is an enum containing all the ids used within the webapp xhtml.
// It could easily be substituted by a string list or similar.
public static String getCompListSpaced( List< UiPnlSubId > compIds ) {
if ( compIds == null || compIds.isEmpty() )
return "" ;
StringBuffer sb = new StringBuffer( ":" ) ;
for ( UiPnlSubId cid : compIds )
sb.append( ComponentUtils.findComponentClientId( cid.name() ) ).append( " " ) ;
return sb.deleteCharAt( sb.length() - 1 ).toString() ; // delete suffixed space
}
called via some other method using it, e.g. like ... update="#{foo.getCompListComputed( 'triggeringCompId' )}".
1: first I tried without too much thinking to return public static String getCompListSpaced0() { return ":#{p:component('table2')}" ; } in an ... update="#{foo.getCompListSpaced0()} expression, which of course (after thinking about how the framework works :) ) is not resolved (returned as is) and may cause the issues with it some users experienced. Also my Eclipse / JBoss Tools environment suggested to write :#{p.component('table2')} ("." instead of ":") which did not help - of course.