I'm trying to convert GET request parameters passed from another view like this:
<f:metadata>
<f:viewParam name="id"
value="#{targetViewBean.fooFromSourceView}"
converter="fooConverter"
converterMessage="Foo converter message"
required="true" requiredMessage="Foo required message"/>
<f:viewAction action="#{targetViewBean.doSomethingWithFoo()}"/>
</f:metadata>
But only the Converter.getAsString(..., Object value) method is called and value is always null, even thou the GET parameter is really sent.
I found BalusC blog post about this and, AFAIK, I followed it to the letter. Still no good. Here's the full code:
Source view
<h:head>
<title>Source view</title>
</h:head>
<h:body>
<ul>
<ui:repeat value="#{sourceViewBean.foos}" var="foo">
<li>
<h:link value="Foo \##{foo.id}" outcome="target-view">
<f:param name="id" value="#{foo.id}" />
</h:link>
</li>
</ui:repeat>
</ul>
</h:body>
Backing bean
#Named #ViewScoped
public class SourceViewBean implements Serializable {
public Collection<Foo> getFoos() {
return Db.INSTANCE.getFoos();
}
private static final long serialVersionUID = 1L;
}
Target view
<f:metadata>
<f:viewParam name="id"
value="#{targetViewBean.fooFromSourceView}"
converter="fooConverter"
converterMessage="Foo converter message"
required="true" requiredMessage="Foo required message"/>
<f:viewAction action="#{targetViewBean.doSomethingWithFoo()}"/>
</f:metadata>
<h:head>
<title>Target view</title>
</h:head>
<h:body>
<h:outputText value="ID: #{targetViewBean.fooFromSourceView.id}" />
</h:body>
Target view backing bean
#Named
#ViewScoped
public class TargetViewBean implements Serializable {
private Foo fooFromSourceView;
public void doSomethingWithFoo() {
System.out.println("Foo is here? " + fooFromSourceView != null);
}
public Foo getFooFromSourceView() {
return fooFromSourceView;
}
public void setFooFromSourceView(Foo fooFromSourceView) {
this.fooFromSourceView = fooFromSourceView;
}
private static final long serialVersionUID = 1L;
}
The converter
#FacesConverter(value = "fooConverter")
public class FooConverter implements Converter {
#Override
public Object getAsObject(
FacesContext context, UIComponent component, String value) {
if (value == null || !value.matches("\\d+")) {
return null;
}
for (Foo foo : Db.INSTANCE.getFoos()) {
if (foo.getId().equals(Integer.parseInt(value))) {
return foo;
}
}
throw new ConverterException(new FacesMessage("No Foo found!"));
}
#Override
public String getAsString(
FacesContext context, UIComponent component, Object value) {
if (!(value instanceof Foo) || ((Foo) value).getId() == null) {
return null;
}
return ((Foo) value).getId().toString();
}
}
I was able to find the problem after taking a look at the actual code you sent. The issue is not with the converter. It's with the xml namespaces at the top of your project. For instance, in source-view.xml you have
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
But they should be
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core">
And target-view.xhtml should be
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
GlassFish seems to change the namespaces for some reason. I didn't try to find out why it behaves like that though so keep that in mind. Anyway, once I changed it, the correct phases were being outputted in GlassFish's output window. So go and make the necessary change where needed.
Note: In case you are wondering why you are getting the following error
The metadata component needs to be nested within a f:metadata tag. Suggestion: enclose the necessary components within <f:metadata>
This seems to be a reported issue with JSF 2.2
Also, I'm not sure why your h:link is nested inside an h:form. It's not needed.
UPDATE
Seems like some of the taglibs are not fully functional or am I reading this wrong ?
https://java.net/jira/browse/JAVASERVERFACES-2868
Related
This question already has an answer here:
Extended #FacesComponent as composite interface componentType renders nothing
(1 answer)
Closed 7 years ago.
I'm trying to build in a composite component in JSF with PrimeFaces.
in src/main/webapp/resources/components I have a component called editableLabel.xhtml
<!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:composite="http://java.sun.com/jsf/composite"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head></h:head>
<h:body>
<composite:interface componentType="editableLabel">
<composite:attribute name="value" required="true"/>
<composite:attribute name="editMode" required="false" default="#{false}" type="java.lang.Boolean"/>
</composite:interface>
<composite:implementation>
<h:panelGroup id="editableLabelComponent">
<h:panelGroup rendered="#{cc.attrs.editMode}">
<p:inputText value="#{cc.attrs.value}"/>
<p:commandButton value="Update" actionListener="#{cc.update}"/>
<p:commandButton value="Cancel" actionListener="#{cc.cancel}"/>
</h:panelGroup>
<p:outputLabel id="display" value="#{cc.attrs.value}" rendered="#{!cc.attrs.editMode}">
<p:ajax event="click" listener="#{cc.toggleEditMode}" update="editableLabelComponent"/>
</p:outputLabel>
</h:panelGroup>
</composite:implementation>
</h:body>
</html>
Backed by a FacesComponent called EditableLabel.java
import javax.el.ValueExpression;
import javax.faces.component.FacesComponent;
import javax.faces.component.UIComponentBase;
import javax.faces.context.FacesContext;
import java.io.Serializable;
/**
* Created by labraham on 1/14/16.
*/
#FacesComponent(value = "editableLabel")
public class EditableLabel extends UIComponentBase implements Serializable {
private static final long serialVersionUID = 108467781935083432L;
private String oldValue = "";
/**
* Constructor
*/
public EditableLabel() {
super();
}
#Override
public String getFamily() {
return "foo.bar.components";
}
/**
*
*/
public void update() {
toggleEditMode();
FacesContext context = FacesContext.getCurrentInstance();
this.oldValue = (String) getValueExpression("value").getValue(context.getELContext());
}
/**
*
*/
public void cancel() {
toggleEditMode();
FacesContext context = FacesContext.getCurrentInstance();
ValueExpression valueExpression = getValueExpression("value");
valueExpression.setValue(context.getELContext(), this.oldValue);
}
/**
*
*/
public void toggleEditMode() {
FacesContext context = FacesContext.getCurrentInstance();
Boolean editModeValue = (Boolean) getValueExpression("editMode").getValue(context.getELContext());
ValueExpression editModeVe = getValueExpression("editMode");
editModeVe.setValue(context.getELContext(), String.valueOf(!editModeValue));
}
}
Yet when I try to stick it in an another file like so
foo.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui" xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:comp="http://java.sun.com/jsf/composite/components"
>
...
<h3>Test</h3>
<comp:editableLabel value="#{foobean.testValue}"/>
It doesn't render. It tried removing the rendered attributes from the component (as well as editmode composite:attribute) and I've verified that it's looking for editableLabel.xhtml in the right place. foobean.testValue is just a string with a default value of "test value" and the appropriate getter and setter.
Why might PrimeFaces refuse to render this composite component?
Edit: I've also tried replacing the primefaces components in the composite component with their JSF equivalents and that didn't work. And I tried removing the ajax calls to see if maybe it was some issue with that. It wasn't.
Edit 2: Its an issue the my FacesComponent but I don't know what. Removing the component type attribute got it to render at least.
So I figured it out thanks to BalusC's answer to Extended #FacesComponent as composite interface componentType renders nothing
I needed to implement NamingContainer and getFamily() in EditableLabel.java
Suppose I have a composite component
<!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:composite="http://java.sun.com/jsf/composite"
`enter code here` xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head></h:head>
<h:body>
<composite:interface componentType="editableLabel">
<composite:attribute name="value" required="true" type="java.lang.String"/>
<composite:attribute name="oldValue" type="java.lang.String"/>
<composite:attribute name="editMode" required="false" default="#{false}" type="java.lang.Boolean"/>
<composite:attribute name="updateListener" required="false" method-signature="void actionListener()"/>
<composite:attribute name="cancelListener" required="false" method-signature="void actionListener()"/>
</composite:interface>
<composite:implementation>
<h:panelGroup id="editableLabelComponent">
<h:panelGroup rendered="#{cc.attrs.editMode}">
<p:inputText value="#{cc.attrs.value}"/>
<p:commandButton value="Update" actionListener="#{cc.update}" update="editableLabelComponent"/>
<p:commandButton value="Cancel" actionListener="#{cc.cancel}" update="editableLabelComponent"/>
</h:panelGroup>
<p:commandLink>
<p:outputLabel id="display" value="#{cc.attrs.value}" rendered="#{!cc.attrs.editMode}"/>
<p:ajax event="click" listener="#{cc.toggleEditMode}" update="editableLabelComponent"/>
</p:commandLink>
</h:panelGroup>
</composite:implementation>
</h:body>
</html>
with a FacesComponent
import org.apache.commons.lang3.StringUtils;
import javax.el.ELContext;
import javax.el.ValueExpression;
import javax.faces.component.FacesComponent;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponentBase;
import javax.faces.component.UINamingContainer;
import javax.faces.context.FacesContext;
import java.io.Serializable;
/**
* Created by labraham on 1/14/16.
*/
#FacesComponent(value = "editableLabel")
public class EditableLabel extends UIComponentBase implements Serializable, NamingContainer {
private static final long serialVersionUID = 108467781935083432L;
public static final String VALUE_ATTRIBUTE = "#{cc.attrs.value}";
public static final String OLD_VALUE_ATTRIBUTE = "#{cc.attrs.oldValue}";
public static final String EDIT_MODE_ATTRIBUTE = "#{cc.attrs.editMode}";
private FacesContext context;
private ELContext elContext;
#Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
/**
*
*/
public void update() {
ValueExpression oldValue = getAttr(OLD_VALUE_ATTRIBUTE, String.class);
String value = (String) getAttr(VALUE_ATTRIBUTE, String.class).getValue(getElContext());
oldValue.setValue(getElContext(), value);
toggleEditMode();
}
/**
*
*/
public void cancel() {
ValueExpression value = getAttr(VALUE_ATTRIBUTE, String.class);
String oldValue = (String) getAttr(OLD_VALUE_ATTRIBUTE, String.class).getValue(getElContext());
value.setValue(getElContext(), oldValue);
toggleEditMode();
}
/**
*
*/
public void toggleEditMode() {
if (StringUtils.isEmpty((String) getAttr(OLD_VALUE_ATTRIBUTE, String.class).getValue(getElContext()))) {
getAttr(OLD_VALUE_ATTRIBUTE, String.class).setValue(getElContext(),
getAttr(VALUE_ATTRIBUTE, String.class).getValue(getElContext())
);
}
ValueExpression editmode = getAttr(EDIT_MODE_ATTRIBUTE, Boolean.class);
editmode.setValue(getElContext(), !((Boolean) editmode.getValue(getElContext())));
}
/**Get value expression for a given attr.*/
private ValueExpression getAttr(final String attribute, final Class<?> attributeType) {
return getContext().getApplication().getExpressionFactory()
.createValueExpression(getElContext(), attribute, attributeType);
}
/**Get ElContext.*/
public ELContext getElContext() {
if (this.elContext == null) {
elContext = getContext().getELContext();
}
return elContext;
}
public void setElContext(final ELContext elContext) {
this.elContext = elContext;
}
/**Get faces context*/
public FacesContext getContext() {
if (this.context == null) {
context = FacesContext.getCurrentInstance();
}
return context;
}
public void setContext(final FacesContext context) {
this.context = context;
}
}
now all instances of this widget will have the baseline functionality for cancel and update as defined by the cancel() and update() functions. However in addition this basic functionality the user may want some additional functionality (for instance calling a webservice on update) which they will add by some sort of backing bean method in the updateListener and/or cancelListener attributes.
My question is Is it possible to call the method that the user attached to the listener attributes programmatically from inside the FacesComponent or am I going about this the wrong way?
Yes, it's available as a MethodExpression typed attribute. All composite attributes are available the usual way by the inherited UIComponent#getAttributes() map. See also How to access Composite Component attribute values in the backing UIComponent?
E.g., to get #{cc.attrs.updateListener} and invoke with no params:
MethodExpression updateListener = (MethodExpression) getAttributes().get("updateListener");
updateListener.invoke(getFacesContext().getELContext(), null);
Unrelated to the concrete problem, the way how you deal with ValueExpression attributes is clumsy. To get #{cc.attrs.oldvalue}, just do:
String oldvalue = (String) getAttributes().get("oldvalue");
To set #{cc.attrs.value}, just do:
getAttributes().put("value", oldvalue);
Having FacesContext and ELContext as instance variables does technically fortunately not harm in this specific construct, but this is fishy, you'd better get them in method local scope. The FacesContext is just available by inherited UIComponent#getFacesContext().
See also:
How can I create a JSF composite component that allows me to read/write to the attributes?
java.lang.IllegalStateException at com.sun.faces.context.FacesContextImpl.assertNotReleased
How can i switch my validator in a component dependence on a boolean.
I have a selectBooleanCheckbox and when its true i want use FirstValidator else i want use SecondValidator. I found nothing about this "special" case.
Nothing special only for example code:
Xhtml:
<?xml version="1.0" encoding="UTF-8"?>
<html 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">
<h:head>
</h:head>
<h:body>
<h:form>
<h:selectBooleanCheckbox value="#{testBean.firstValidator}"/>
<h:inputText>
<f:validator validatorId="FirstValidator" />
</h:inputText>
<h:commandButton value="Test" />
<h:messages />
</h:form>
</h:body>
</html>
Bean:
#ManagedBean
#ViewScoped
public class TestBean implements Serializable{
private boolean firstValidator;
public boolean isfirstValidator() {
return firstValidator;
}
public void setfirstValidator(boolean firstValidator) {
this.firstValidator = firstValidator;
}
}
Validator1:
#FacesValidator("FirstValidator")
public class FirstValidator implements Validator{
#Override
public void validate(FacesContext context, UIComponent component,
Object value) throws ValidatorException {
String valueAsString = (String) value;
if(valueAsString.contains("a")){
throw new ValidatorException(new FacesMessage("Fail!"));
}
}
}
Validator2:
#FacesValidator("SecondValidator")
public class SecondValidator implements Validator{
#Override
public void validate(FacesContext context, UIComponent component,
Object value) throws ValidatorException {
String valueAsString = (String) value;
if(valueAsString.contains("b")){
throw new ValidatorException(new FacesMessage("Fail2!"));
}
}
}
Just set/disable the validator depending on checkbox's value. You only need to make sure that you pick the checked value as available during view build time (which runs during restore view phase). So you definitely can't use the model value #{testBean.firstValidator} for this (which is only set during update model values phase). You'd need to determine the HTTP request parameter instead. It's empty if the checkbox is unchecked, otherwise it's not empty.
First bind the checkbox component to the view (not to a bean!) via binding attribute:
<h:selectBooleanCheckbox binding="#{checkbox}" ... />
This way the request parameter can be dynamically obtained as #{param[checkbox.clientId]}.
Now you can use either conditional setting of validator ID:
<f:validator validatorId="#{empty param[checkbox.clientId] ? 'firstValidator' : 'secondValidator'}" />
Or conditional setting the validator's disabled attribute:
<f:validator validatorId="firstValidator" disabled="#{not empty param[checkbox.clientId]}" />
<f:validator validatorId="secondValidator" disabled="#{empty param[checkbox.clientId]}" />
Note that I altered the validator IDs as per Java instance variable naming conventions. You also don't do as follows in normal Java code, right?
Validator FirstValidator = new FirstValidator();
I need to invoke a method of backing component(#facescomponent) of composite component. I see others do this in articles but none of them has ever worked for me.
this how I invoke:
<ui:component 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:cc="http://java.sun.com/jsf/composite">
<cc:interface componentType="formField"/>
<cc:implementation>
<h:commandButton value="doIt" action="#{cc.myAction}" ></h:commandButton>
</cc:implementation>
</ui:component>
and this is the backing component.
#FacesComponent("formField")
public class Field extends UICommand implements NamingContainer {
public Field() {
}
#Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
public String myAction() {
System.out.println("in action");//not printed
return null;
}
}
Shouldn't myAction method be invoked? What did I do wrong?
you do an invoke for property, for method need to use:
action="#{cc.myAction()}"
Original question is below, but as I have come up with a more minimal example to demonstrate this problem, and figured it should go at the top.
Anyway, it appears that ui:repeat tags are processed before checking to see if parent elements are actually rendered. To recreate this, here is the facelet (minimalTest.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:f="http://java.sun.com/jsf/core">
<h:head>
<title>Test JSF <ui:repeat> inside <h:panelGroup rendered="false"></title>
</h:head>
<h:body>
<h:form>
<h1>Testing</h1>
<h:panelGroup rendered="false">
<span>#{minimalTestBean.alsoThrowsException}</span>
<ul>
<ui:repeat value="#{minimalTestBean.throwsException}" var="item">
<li>#{item}</li>
</ui:repeat>
</ul>
</h:panelGroup>
</h:form>
</h:body>
</html>
With using this bean (MinimalTestBean.java):
package com.lucastheisen.beans;
import java.io.Serializable;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class MinimalTestBean implements Serializable {
private static final long serialVersionUID = 9045030165653014015L;
public String getAlsoThrowsException() {
throw new RuntimeException( "rendered is false so this shouldnt get called either" );
}
public List<String> getThrowsException() {
throw new RuntimeException( "rendered is false so this shouldnt get called" );
}
}
From this example you can see that the h:panelGroup that contains the ui:repeat is statically set to rendered=false which I would assume would mean that none of the EL expressions inside of that h:panelGroup would get executed. The EL expressions just call getters which throw a RuntimeException. However, the ui:repeat is actually calling the getter for its list thus causing the exception even though it should not be getting rendered in the first place. If you comment out the ui:repeat element, no exceptions get thrown (even though the other EL expression remains in the h:panelGroup) as I would expect.
Reading other questions here on stackoverflow leads me to believe that is likely related to the oft-referred-to chicken/egg issue, but I am not sure exactly why, nor what to do about it. I imagine setting the PARTIAL_STATE_SAVING to false might help, but would like to avoid the memory implications.
---- ORIGINAL QUESTION ----
Basically, I have a page that conditionally renders sections using <h:panelGroup rendered="#{modeXXX}"> wrapped around <ui:include src="pageXXX.xhtml" /> (per this answer). The problem is that if one of the pageXXX.xhtml has a <ui:repeat> inside of it, it seems to get processed even when the containing <h:panelGroup> has rendered=false. This is a problem because some of my sections rely on having been initialized by other sections that should be visited before them. Why is the included pageXXX.xhtml getting processed?
This is a painful bug and incredibly hard to boil down to a small example, but here is the most minimal case I could build that demonstrates the issue. First a base page:
<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">
<h:head>
<title>Test JSF <ui:include></title>
</h:head>
<h:body>
<h:form>
<h1>#{testBean.title}</h1>
<h:panelGroup rendered="#{testBean.modeOne}">
<ui:include src="modeOne.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{testBean.modeTwo}">
<ui:include src="modeTwo.xhtml" />
</h:panelGroup>
</h:form>
</h:body>
</html>
As you can see this page will conditionally include either the modeOne page or the modeTwo page based upon the value in the testBean bean. Then you have modeOne (the default):
<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">
<ui:composition>
<span>Okay, I'm ready. Take me to </span>
<h:commandLink action="#{testBean.setModeTwo}">mode two.</h:commandLink>
</ui:composition>
</html>
Which in my real world app would be a page that sets up things needed by modeTwo. Once set up, an action on this page will direct you to modeTwo:
<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">
<ui:composition>
<div>Here is your list:</div>
<ui:repeat value="#{testBeanToo.list}" var="item">
<div>#{item}</div>
</ui:repeat>
</ui:composition>
</html>
The modeTwo page basically presents a details for the modeOne page in a ui:repeat as the actual information is in a collection. The main managed bean (TestBean):
package test.lucastheisen.beans;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class TestBean implements Serializable {
private static final long serialVersionUID = 6542086191355916513L;
private Mode mode;
#ManagedProperty( value="#{testBeanToo}" )
private TestBeanToo testBeanToo;
public TestBean() {
System.out.println( "constructing TestBean" );
setModeOne();
}
public String getTitle() {
System.out.println( "\ttb.getTitle()" );
return mode.getTitle();
}
public boolean isModeOne() {
return mode == Mode.One;
}
public boolean isModeTwo() {
return mode == Mode.Two;
}
public void setModeOne() {
this.mode = Mode.One;
}
public void setModeTwo() {
testBeanToo.getReadyCauseHereICome();
this.mode = Mode.Two;
}
public void setTestBeanToo( TestBeanToo testBeanToo ) {
this.testBeanToo = testBeanToo;
}
private enum Mode {
One("Mode One"),
Two("Mode Two");
private String title;
private Mode( String title ) {
this.title = title;
}
public String getTitle() {
return title;
}
}
}
Is the bean for all the main data, and the TestBeanToo bean would be for the details:
package test.lucastheisen.beans;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class TestBeanToo implements Serializable {
private static final long serialVersionUID = 6542086191355916513L;
private ObjectWithList objectWithList = null;
public TestBeanToo() {
System.out.println( "constructing TestBeanToo" );
}
public String getTitle() {
System.out.println( "\ttb2.getTitle()" );
return "Test Too";
}
public List<String> getList() {
System.out.println( "\ttb2.getList()" );
return objectWithList.getList();
}
public void getReadyCauseHereICome() {
System.out.println( "\ttb2.getList()" );
objectWithList = new ObjectWithList();
}
public class ObjectWithList {
private List<String> list;
public ObjectWithList() {
list = new ArrayList<String>();
list.add( "List item 1" );
list.add( "List item 2" );
}
public List<String> getList() {
return list;
}
}
}
<ui:repeat> does not check the rendered attribute of itself (it has actually none) and its parents when the view is to be rendered. Consider using Tomahawk's <t:dataList> instead.