Obtaining the clientId of the parent of a JSF2 composite component - jsf-2

I've got the following code:
<h:dataTable id="dt" value="#{somelist}" var="entry">
<h:column>
#{entry.title}
</h:column>
<h:column>
<h:commandLink id="lnk">
<mycomp:doSomething id="dummy" />
</h:commandLink>
</h:column>
</h:dataTable>
My composite component (mycomp:doSomething) looks like this:
<?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">
<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:interface>
<composite:implementation >
<script type="text/javascript">
// #{component.parent.clientId}
</script>
</composite:implementation>
</html>
I would expect the output (#{component.parent.clientId}) to be something similar to this: dt:0:lnk but instead it returns dt:0:dummy i.e. the client ID of the composite component.
How do I get the ID of the real parent tag?

Use #{cc.parent.clientId} instead. All content inside composite:implementation is inside a UIPanel that is on a facelet inside the composite component base instance, which usually is a NamingContainer.
UPDATE: Checking the code, cc.parent resolves the parent composite component instead of the immediate parent. It seems to be an old implementation detail, but it is not mentioned in the spec. The solution proposed in this answer does not work :(.
See http://lists.jboss.org/pipermail/jsr-314-open-mirror/2010-February/002474.html
You can bypass the resolution of cc.parent, providing a custom component class extending UINamingContainer and adding this:
<composite:interface componentType="my.custom.ComponentBaseClass">
then add a getter like
public UIComponent getImmediateParent()
{
return getParent();
}
and finally use #{cc.immediateParent.clientId}. It should work in this way.

Related

JSF Bookmarkable URL to update ui:decorate value

Need help here. I'm trying to make my current project bookmarkable. My current design can basically be summed up in this code snippet:
<?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">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<f:metadata>
<f:viewParam name="contentUrl" value="#{navigationBean.contentUrl}"/>
</f:metadata>
<h:body>
<ui:composition template="/views/template/template.xhtml">
<ui:define name="leftpane">
<ui:include src="/views/admin/menu_administrator.xhtml"/>
</ui:define>
<ui:define name="rightpane">
<p:growl showDetail="true" sticky="false" />
<ui:decorate template="/views/admin/content/#{navigationBean.contentUrl}.xhtml"/>
</ui:define>
</ui:composition>
</h:body>
</html>
So I have this template to make the site 30/70 look having the "leftpane" contain the menu and the "rightpane" to display the output content. What I want is to be able to change the output in the "rightpane" depending on the URL sent:
www.mysite.com/projectitle/views/admin/Administrator.xhtml?faces-redirect=true&contentUrl=cont_admin_rapptmnttype
Whatever will be constructed in this url: /views/admin/content/#{navigationBean.contentUrl}.xhtml on the "rightpane" also has a corresponding backing bean to generate the needed output
I'm using Primefaces3.5, MyFaces2.0, WAS8.5
Hope someone could help me out on this. Thanks.
UPDATE:
I am using a p:menuitem to set the contentUrl like
<p:menuitem value="Appointment Type" id="cont_admin_rapptmnttype"
ajax="false" outcome="#{navigationBean.currentMode}" >
<f:param name="contentUrl" value="cont_admin_rapptmnttype"/>
</p:menuitem>
But when I click on the menuitem I get a Stackoverflow exception which, as it turns, is caused by:
<ui:decorate template="/views/admin/content/#{navigationBean.contentUrl}.xhtml"/>
Which is the one I'm trying to update.
Here is the recurring exception in the stacktrace:
at org.apache.myfaces.view.facelets.tag.ui.DecorateHandler.apply(DecorateHandler.java:137)
at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:51)
at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:59)
at org.apache.myfaces.view.facelets.tag.jsf.ComponentTagHandlerDelegate.apply(ComponentTagHandlerDelegate.java:324)
at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:54)
at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:51)
at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:59)
at org.apache.myfaces.view.facelets.tag.jsf.ComponentTagHandlerDelegate.apply(ComponentTagHandlerDelegate.java:324)
at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:54)
at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:51)
at org.apache.myfaces.view.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:150)
at org.apache.myfaces.view.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:57)
at org.apache.myfaces.view.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:45)
at org.apache.myfaces.view.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:322)
at org.apache.myfaces.view.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:369)
at org.apache.myfaces.view.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:347)
at org.apache.myfaces.view.facelets.impl.DefaultFaceletContext.includeFacelet(DefaultFaceletContext.java:215)

Updating p:graphicImage every n seconds

I was wondering if someone could either explain or point me to a good resource that will help me understand how to update a p:graphicImage in Primefaces 5.0. What I'm trying to do is pretty simple.
<p:graphicImage value="myImage.png"/>
The filename never changes, but it will be updated every n seconds. I'm trying to figure out the easiest way to update that image every n seconds. In this case we'll say every 5.
tyia
Update:
I've tried the suggestions below but poll isn't updating. I've tested this in IE, FF, and Chrome. I'm using the sample code on the prime faces. Here's my bean:
#ManagedBean
#ViewScoped
public class CounterView implements Serializable {
private int number;
public int getNumber() {
return number;
}
public void increment() {
System.out.println("test");
number++;
}
}
I'm outputting to the console to see if increment() is ever executed, which it isn't.
Here's my xhtml:
<?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">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title></title>
</h:head>
<h:body>
<h:form>
<p>Welcome, #{loginBean.uname}</p>
<p:commandButton action="#{loginBean.logout}" value="Logout" ajax="false"></p:commandButton>
<br/>
<h:form>
<h:outputText id="txt_count" value="#{counterView.number}" />
<p:poll interval="3" listener="#{counterView.increment}" update="txt_count" />
</h:form>
</h:form>
</h:body>
</html>
The above is the page that I'm redirecting to after a successful login. All output is correct except for txt_count....it stays at 0. I took the image out to get this working before applying it to the image update.
Update 2:
Got the int counter working
<?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">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title></title>
</h:head>
<h:body>
<h:form>
<p>Welcome, #{loginBean.uname}</p>
<p:commandButton action="#{loginBean.logout}" value="Logout" ajax="false"></p:commandButton>
<br/>
<h:outputText id="txt_count" value="#{counterView.number}" />
<p:poll interval="3" listener="#{counterView.increment}" update="txt_count" />
</h:form>
</h:body>
</html>
You might use a poll component with a listener method that changes the image.
<p:poll interval="3" listener="#{your_method_to_change_the_image()}" update="myImage" />
<p:graphicImage id="myImage" value="myImage.png"/>
Disclaimer : Not tested.
According to Primefaces user guide p. 247 you can use a p:imageSwitch for a slideshow. For example:
p:imageSwitch effect="FlyIn">
<p:graphicImage value="/images/nature1.jpg" />
<p:graphicImage value="/images/nature2.jpg" />
<p:graphicImage value="/images/nature3.jpg" />
<p:graphicImage value="/images/nature4.jpg" />
</p:imageSwitch>
You can also set the speed. If I understand you correctly and you change the image serverside I guess you can just alternate between 2 images with the same url. If the browser reads the cached image instead of the updated one I think you can append the current date to the url.

How work auto complite custom component?

A have found sample on internet(IBM site http://www.ibm.com/developerworks/web/library/j-jsf2fu-0410/index.html#listing1) and on some book that with JSF can make auto complete drop down list. Like on google search page. The main point of this is in using composite component page. It look like:
<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:composite="http://java.sun.com/jsf/composite">
<!-- INTERFACE -->
<composite:interface>
<composite:attribute name="value" required="true"/>
<composite:attribute name="completionItems" required="true"/>
</composite:interface>
<!-- IMPLEMENATION -->
<composite:implementation>
<div id="#{cc.clientId}">
<h:outputScript library="javascript"
name="prototype-1.6.0.2.js" target="head"/>
<h:outputScript library="javascript"
name="autoComplete.js" target="head"/>
<h:inputText id="input" value="#{cc.attrs.value}"
onkeyup="com.corejsf.updateCompletionItems(this, event)"
onblur="com.corejsf.inputLostFocus(this)"
valueChangeListener="#{autocompleteListener.valueChanged}"/>
<h:selectOneListbox id="listbox" style="display: none"
valueChangeListener="#{autocompleteListener.completionItemSelected}">
<f:selectItems value="#{cc.attrs.completionItems}"/>
<f:ajax render="input"/>
</h:selectOneListbox>
<div>
</composite:implementation>
</ui:composition>
My questions are:
Why we use ui:composition tags with out any parameters.
We have in h:inputText defined valueChangeListener, realized over backend class which has method public void valueChanged(ValueChangeEvent e) with these two lines
UIInput input = (UIInput) e.getSource();
UISelectOne listbox = (UISelectOne) input.findComponent("listbox");
If (UIInput)e.get source return component inputText with id="name". How possible next line
UISelectOne listbox = (UISelectOne)input.findComponent("listbox");
For the first question: <ui:composition template="..."> renders the content's of this tag into the specified template. Since you have no template here, the attribute isn't needed.
For the second question: findComponent searches for the given id in the enclosing NamingContainer, which is your composite component (check the Javadoc for the full algorithm). It's not like jQuery where it only searches "below" the given component.

locale can't be changed

I'm trying to change Locale using primefaces in vain, here's my bean code :
// more imports here
#ManagedBean
#SessionScoped
public class DateBean implements Serializable{
private Date startDate, endDate;
private Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
public void setLocale(Locale locale) {
this.locale = locale;
}
public Locale getLocale(){
return locale;
}
public void changeLocale(String loc){
FacesContext context = FacesContext.getCurrentInstance();
locale = new Locale(loc);
context.getViewRoot().setLocale(locale);
}
}
facelet :
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!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:p="http://primefaces.org/ui"
xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">
<f:view locale="#{dateBean.locale}">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Insert title here</title>
<h:outputScript library="scripts" name="#{dateBean.locale}.js"></h:outputScript>
</h:head>
<h:body>
<h:form>
<p:commandButton value="de" action="#{dateBean.changeLocale('de')}" >
<p:ajax update="#form" process="#form"></p:ajax>
</p:commandButton>
<p:calendar id="cc" value="#{dateBean.startDate}" required="true" showOn="both"
requiredMessage="Start date required"/>
<p:message for="cc"></p:message>
</h:form>
</h:body>
</f:view>
</html>
Calendar locale does not change to deutsch when i click on the locale button, and i got no exception .
However it's like a breeze doing this task using old JSF2.* CommandButton component this way :
<h:commandButton value="portugal" action="#{dateBean.changeLocale('pt')}" >
<f:ajax render="#form"></f:ajax>
</h:commandButton>
May you guys help me figure it out please ?
Primefaces library doesn't provide German translation for its components. You need to download the javascript piece and attach it to your code. Then, make the calendar use the locale you want. Take a look at this site and here you have more info about your issue.
You also are including a Javascript file depending on your locale (<h:outputScript library="scripts" name="#{dateBean.locale}.js">) that makes the javascript file to be included dinamically depending on your locale. Since you're only refreshing the h:form part with your ajax request, you could get in trouble with that, since this tag is rendered with the whole view, so your translation file is not available for your locale at the moment. Appropiate solution: just include all the javascript files you need since the begining.

Accessing JSF2 composite component attributes in backing component

I'm developing a JSF2/Primefaces app and I'm having trouble with accessing attributes defined in an interface of a composite component in this component's backing bean.
My component is defined as follows:
<!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 componentType="testComponent">
<composite:attribute name="text" required="true" type="java.lang.String" />
</composite:interface>
<composite:implementation>
<h:outputText value="Passed text is: #{cc.attrs.text}" />
</composite:implementation>
</html>
It is stored in a file called text.xhtml located in: application/src/main/webapp/resources/my_component directory.
I use this component on another page (which is a Facelets composition element) like so:
<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:myc="http://java.sun.com/jsf/composite/my_component"
template="./resources/templates/template.xhtml">
<ui:define name="content">
<h:form id="products">
<myc:test id="test" text="A text" />
</h:form>
</ui:define>
</ui:composition>
The backing component class is defined as follows:
package my.application.component;
import javax.faces.component.FacesComponent;
import javax.faces.component.UINamingContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#FacesComponent ( value="testComponent" )
public class TestComponent extends UINamingContainer {
Logger log = LoggerFactory.getLogger(TestComponent.class);
public TestComponent() {
log.debug("TestComponent constructor");
log.debug("getAttributes().size(): " + getAttributes().size());
}
}
The component itself works as expected. The using page renders Passed text is: A text output.
Also, logger output displays log messages from TestComponent constructor, so it seems that the component xml definition is correctly bound with the TestComponent class.
Now, the problem is that the getAttributes() method invoked in TestComponent constructor always returns a zero-sized map.
If I understand this correctly, I should be able to access the text attribute declared in component's interface using a call:
getAttributes().get("text");
in the TestComponent class, but it always returns null as the attributes map is empty.
I also tried to access the text attribute using a call:
String text = FacesContext.getCurrentInstance().getApplication().
evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{cc.attrs.text}", String.class));
but it also resolves to null.
What am I doing wrong? Any tips will be much appreciated as I have no idea what to try next.
/Tukasz.
My guess is that the constructor is too early to reference those attributes.
JSF will construct an instance of the backing component first, and will then at some point give it a reference to its attributes. In a method that's called later, eg the encode method, you should have access to them.

Resources