How does the "collapsed" attribute of p:fieldset work? - jsf

I'm using PrimeFaces' p:fieldset component and I want to control, from my bean, either or not it's collapsed. I expected the collpased property to do this job, but this is not working.
On the other hand, a "binding" seems to correctly mirror the component's state:
My Bean
#Named
#RequestScoped
public class TestBean {
//with get/set
private boolean collapsed;
//with get/set
private Fieldset fieldset;
}
My page:
<h:form>
<p:fieldset
id="togglebleFieldset"
legend="Toggleable Fieldset"
toggleable="true"
binding="#{testBean.fieldset}"
collapsed="#{testBean.collapsed}">
fieldset content
<p:ajax event="toggle" update="#form"/>
</p:fieldset>
<h:outputText value="Value is never updated: #{testBean.collapsed}" />
<br/><h:outputText value="Binding correctly reflects the state: #{testBean.fieldset.collapsed}" />
</h:form>
For reasons beyond the scope of this question, using the binding solution will be a little bit more complicated to me.
Why isn't #{testBean.collapsed} being update with the component's collapsed value?
(Using versions 6.0 and 6.2 of PrimeFaces)

Related

Dynamic rendering of ui:include won't work when ui:repeat is used in included facelet

Hello,
I'm putting ui:include inside h:panelGroup and rendering it dynamically when required.
The usual assumption and theory is, ManagedBean associated with the included page should not get initialized when ui:include is not rendered.
This is not happening when I use ui:repeat inside included page.
Here is a Example to repeat the Issue:
page.1.xhtml
<h:body>
<h:form>
<p:outputLabel value="#{mBeanOne.beanOnetxt}"/><br/>
</h:form>
<h:panelGroup rendered="false" layout="block">
<ui:include src="page2.xhtml"/>
</h:panelGroup>
</h:body>
MBeanOne.java
#ManagedBean
#ViewScoped
public class MBeanOne implements Serializable{
private String beanOnetxt;
public MBeanOne() {
System.out.println("MBeanOne - Constructor");
}
#PostConstruct
public void init(){
beanOnetxt = "This is Managed Bean 1";
System.out.println("MBeanOne - Postconstruct");
}
//SETTERS and GETTERS
}
page2.xhtml
<h:body>
<h:outputText value="#{mBeanTwo.beanTwotxt}"/><br/>
<ui:repeat var="var" value="#{mBeanTwo.versionList}">
<h:outputText value="#{var}"/><br/>
</ui:repeat>
</h:body>
MBeanTwo.java
#ManagedBean
#ViewScoped
public class MBeanTwo implements Serializable{
private String beanTwotxt;
private List<String> versionList;
public MBeanTwo() {
System.out.println("MBeanTwo - Constructor");
}
#PostConstruct
public void init(){
beanTwotxt = "This is Managed Bean 2";
versionList = new ArrayList<String>();
versionList.add("Playground");
versionList.add("Kestrel");
versionList.add("Merlin");
versionList.add("Tiger");
System.out.println("MBeanTwo - Postconstruct");
}
//SETTER and GETTER
}
As you can see in page1.xhtml I have use rendered="false" for h:paneGroup which encapsulates ui:include, but still MBeanTwo is getting initialized when I load page1.xhtml.
If I remove ui:repeat from page2.xhtml then MBeanTwo is not getting initialized.
Is this a bug in JSF, if so any workaround available?
Versions used and tested:
Primefaces 3.5
JSF 2.1.13 and 2.2.0-m05
The <ui:include /> piece is not relevant in your question, it could be everything done in the same view with identical behaviour.
Anyway, it seems that <ui:repeat /> tag doesn't check its parents rendered attributes before doing bean initialization. However, the mBeanTwo#getVersionList method never gets evaluated, just the managed bean is created. That could bring you to a slowdown if you perform data access when you construct your bean, but never should break your view. I'm able to reproduce the problem in Mojarra 2.1.x versions, however they have fixed it for 2.2.x latest minors.
Seems a Mojarra implementation bug rather than an expected behaviour.
See also:
JSF ui:repeat included by ui:include wrapped in h:panelGroup with conditional rendering... A mouthfull

selectOneMenu invoked ONLY twice in a multipart/form-data

I have a JSF composite component which includes as a root an h:form. The form has many components among of which are selectOneMenu and a h:inputFile. When I set enctype="multipart/form-data" on the form, the valuechangelistener of the selectOneMenu is invoked ONLY for two value-changing events. Later, however I interact with the menu, the value change listener is not invoked at all. However, if I remove the enctype="multipart/form-data" every thing works fine. I have to keep enctype="multipart/form-data" because I have a file upload component.
Here is my Bean :
#Model
#ViewScoped
public class TransactionBean implements Serializable {
private Part inReceiptFilePart;
/*setter and getter*/
private TransactionType transactionType;
/*setter and getter*/
private final TransactionType transTypeList[] = {
TransactionType.COMPLETE,TransactionType.TECHNICAL,TransactionType.SUBMUNICIPALITY_TECHNICAL, TransactionType.COMPLAINT, TransactionType.FOLLOWUP_COUNCIL, TransactionType.FOLLOWUP_MANAGEMENT
};
public TransactionType[] getTransTypeList() {
return transTypeList;
}
public void transactionTypeChanged(ValueChangeEvent event) {
... /// some code
}
}
And here is the JSF composite component :
<h:form id="entryForm" enctype="multipart/form-data">
<p:selectOneMenu id="transType" value="#{transactionBean.transactionType}" style="direction: ltr" valueChangeListener="#{transactionBean.transactionTypeChanged}">
<f:ajax execute="transType" render="#form" > </f:ajax>
<f:selectItems value="#{transactionBean.transTypeList}" var="tt" itemLabel="#{tt.arName}">
</f:selectItems>
</p:selectOneMenu>
<h:inputFile value="#{transactionBean.inReceiptFilePart}" > </h:inputFile>
<p:commandButton id="insertTrans" value="أدخل المعاملة" action="#{transactionBean.insertTransaction}" ajax="false">
</p:commandButton>
</h:form>
The environment is JSF 2.2, Glassfish 4.0 and primefaces 3.5.
Please help me. I am stuck for three days on this problem.
Thanks
This is very strange behavior!
Try changing valueChangeListener event to an AJAX call.
<p:selectOneMenu id="transType" value="#{transactionBean.transactionType}" style="direction: ltr" >
<p:ajax event="change" partialSubmit="true" update="#form" listener="#{transactionBean.transactionTypeChanged}"/>
<f:selectItems value="#{transactionBean.transTypeList}" var="tt" itemLabel="#{tt.arName}" />
</p:selectOneMenu>
Primefaces's AJAX component is behavior component that extends JSF AJAX.
It adds and manages new events (e.g. valueChange); it also reattach javascript events to DOM element automatically.
Your case is that jsf's ajax does not rebind the valueChange Listener to "transType" selectOneMenu when the form is mutipart! (It's very strange, because the behavior should be the same of those ajax event, weather the form is mutipart or www-form-encoded!

JSF lazy loading component value

Consider a simple h:outputText component:
<h:outputText value="#{myBean.myValue}"/>
How can I lazy load that value after the page has been rendered, and display custom 'ajax loading' icon instead of the value while this is being done?
I am using PrimeFaces 3.5 in my project so any PF-specific implementation will be welcome.
A suggest to do this by calling remoteCommand after on page load (it is done by setting autoRun attribute to true) and update your outputText.
private String myValue;
// getter and setter
public void initMyValue() {
// init myValue
}
On page you should have ajaxStatus component for viewing loading image, and your outputText. Also there should be p:remoteCommand component:
<p:ajaxStatus style="width:16px;height:16px;" id="ajaxStatusPanel">
<f:facet name="start">
<h:graphicImage value="ajaxloading.gif" />
</f:facet>
<f:facet name="complete">
<h:outputText value="" />
</f:facet>
</p:ajaxStatus>
<h:outputText id="myText" value="#{myBean.myValue}"/>
<p:remoteCommand autoRun="true" actionListener="#{myBean.initMyValue}" update="myText"/>
EDIT: I supposed that you want to lazy load value of outputText because it contains some long running calculations, but if you want to completely deffer rendering of outputText first add boolean property in your backing bean, and set this property to true at the end of initMyValue method:
private boolean loaded;
// getter and setter
public void initMyValue() {
// init myValue
loaded = true;
}
on the page reorganize it as follows:
<h:panelGroup id="myPanel" layout="block">
<h:graphicImage value="ajaxloading.gif" rendered="#{!myBean.loaded}"/>
<h:outputText value="#{myBean.myValue}" rendered="#{myBean.loaded}"/>
</h:panelGroup>
<p:remoteCommand autoRun="true" actionListener="#{myBean.initMyValue}" update="myPanel"/>
You can use a BlockUI to conditionally block the component while it loads.
Define a preRenderComponent event on the <h:outputText/>
<h:outputText id="myText">
<f:event name="preRenderComponent" id="started"/>
</h:outputText>
Define a <p:blockUI/> with the id of the event as the trigger
<p:blockUI block="myText" trigger="started" />
You can customize the blockui to display an image or whatever.
A word of caution: I presume you require this because you're doing some heavy lifting in the getter of that component. Know that the getter will be called several times in the lifecycle of that page. So hiding the fact that the operation is taking a long time will not change the fact. A better design would be to preload and cache the value for that component in a durable scope, rather than the theatrics of a "loading" throbber.
This is how I ended up implementing it:
<h:panelGroup id="loginLocation">
<p:graphicImage library="assets" name="small-kit-loader.gif" width="16" height="16" rendered="#{empty mybean.lastLoginLocation}"></p:graphicImage>
<h:outputText value="#{myBean.lastLoginLocation}" rendered="#{!empty myBean.lastLoginLocation}"/>
</h:panelGroup>
<p:remoteCommand global="false" actionListener="#{actionBean.getUserLoginLocation(myBean.selectedUser)}" name="refreshLoginLocation" id="rc1" autoRun="true" update="loginLocation" process="#this"></p:remoteCommand>
Personally I am not entirely happy with this implementation:
lazy loading state is stored server-side, not client-side where it should be
I have to implement separate method on my backing bean (getUserLoginLocation) to retrieve the value, and explicitly store it in another property (lastLoginLocation). It would have been much cleaner just to have a single getter that is lazy-called after rendering the page in browser
Not easily reusable - depends on backing bean 'loaded' flag (#{empty myBean.lastLoginLocation} in this case), and requires action listener to actually set the value. Any composite component based on this approach would also depend on specific code in backing bean.
Any recommendations on how to improve this code are welcome! :)

JSF, AJAX not rendering

Why after selecting an item in this code, the cities component does not get rendered?
<h:form prependId="false">
<h:panelGrid columns="1">
<h:selectOneMenu value="#{enumBeanStatus.selectedRegion}">
<f:selectItems id="selectItem" value="#{enumBean.regions}" var="region" itemLabel="#{region.label}"/>
<f:ajax listener="#{enumBean.loadCities}" render="cities"/>
</h:selectOneMenu>
<h:outputText id="cities" value="#{enumBean.cities}"/>
</h:panelGrid>
</h:form>
It does send a POST with the selected Region, model gets updated correctly, but the <h:outputText> Component is not rendered.
One of the backing beans:
#Named
public class EnumBean {
private List<Region> regions;
private List<City> cities;
#Inject
EnumBeanStatus enumBeanStatus; //This one is CDI #ApplicationScoped & #Named
// Code...
public void loadCities(){
setCities(City.getCitiesByRegion(enumBeanStatus.getSelectedRegion()));
}
// Getters and Setters
}
Remove prependId="false" from the <h:form>. It prevents <f:ajax> from resolving the right component based on a relative client ID.
See also:
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
UIForm with prependId="false" breaks <f:ajax render>

How to access component's children during a #PostConstruct method?

I want to handle all <p:panel> components inside the <h:panelGroup> in the backing bean. I have bound the <h:panelGroup> to a backing bean property. But during the #PostConstruct method the property is null. During the setter of the property setPanel(), the component has no children. If I submit something using a button, then I can get the panel's children.
What do I have to do to get the component's children during the #PostConstruct method?
View:
<h:panelGroup binding="#{wiz.panel}">
<p:panel header="one">
<h:outputText value="primeiro" />
</p:panel>
<p:panel header="two">
<h:outputText value="segundo" />
<h:inputText />
</p:panel>
<p:panel header="three">
<h:outputText value="terceiro" />
</p:panel>
<p:panel header="four">
<h:outputText value="quarto" />
</p:panel>
</h:panelGroup>
Backing bean
#PostConstruct
public void init() {
if (getPanel() != null) {
for (UIComponent comp : getPanel().getChildren()) {
if (comp instanceof Panel) {
System.out.println(((Panel) comp).getHeader());
}
System.out.println("not a panel child");
}
} else {
System.out.println("panel is null");
}
}
That is not possible. The #PostConstruct can be invoked long before the component tree is finished building. Rather hook on the preRenderView event. At that point the view is guaranteed to be already built. You can attach an event listener method by <f:event> in the view as follows:
<f:event type="preRenderView" listener="#{bean.init}" />
Don't forget to remove the #PostConstruct annotation from the init() method or to rename/split the method if necessary.
Needless to say that this approach is fishy. I suggest to rethink your approach and if necessary ask a new question wherein you state the functional requirement in detail. Perhaps the ultimate answer would be just using plain EL and/or rendered attribute.

Resources