Dynamic <ui:include src> depending on <ui:repeat var> doesn't include anything - jsf

I am new to JSF and I am struggling with dynamicaly rendering included pages. My code looks like this:
MenuBean
#ViewScoped
public class MenuBean implements Serializable {
private MenuItem[] menuItems = new MenuItem[] {
new MenuItem("page_1", "/page_1.xhtml"),
new MenuItem("page_2", "/page_2.xhtml"),
};
private String selectedItemLabel;
//...
}
MenuItem
public class MenuItem implements Serializable {
private String label;
private String page;
//...
}
index.xhtml
<ui:repeat var="menuItem" value="#{menuBean.menuItems}">
<h:panelGroup rendered="#{menuBean.selectedItemLabel eq menuItem.label}" layout="block">
<h:outputText value="#{menuBean.selectedItemLabel}" />
<ui:include src="#{menuItem.page}" />
</h:panelGroup>
</ui:repeat>
The result is 2 buttons rendered. Whenever I click any button the label inside conditionaly rendered panelGroup appears but included page doesn't. If I change 'menuItem1' var from first ui:repeat it works but it is really unpredictable. For example if I hardcode setSelectedItemLabel parameter to 'page_1' then when I click to button_1 page_1 is displayed but even if I click to button_2 page_2 (!?) is displayed...

You're facing a view build time vs view render time problem. This is essentially the same problem which is already answered in detail in JSTL in JSF2 Facelets... makes sense? In that answer, replace "JSTL" with "ui:include". To the point, the <ui:repeat> runs during view render time, while the <ui:include> has already run during view build time before.
You'll understand that the only solution is to replace the <ui:repeat> by another tag which runs during view build time, such as JSTL <c:forEach>.
Note that I don't guarantee that it will solve the concrete functional requirement which you've in mind. Using JSTL may have undesirable "side effects" (which are however explainable, understandable and workaroundable).
See also:
How to ajax-refresh dynamic include content by navigation menu? (JSF SPA)

Related

How to set a dynamic value for ui:param [duplicate]

I am new to JSF and I am struggling with dynamicaly rendering included pages. My code looks like this:
MenuBean
#ViewScoped
public class MenuBean implements Serializable {
private MenuItem[] menuItems = new MenuItem[] {
new MenuItem("page_1", "/page_1.xhtml"),
new MenuItem("page_2", "/page_2.xhtml"),
};
private String selectedItemLabel;
//...
}
MenuItem
public class MenuItem implements Serializable {
private String label;
private String page;
//...
}
index.xhtml
<ui:repeat var="menuItem" value="#{menuBean.menuItems}">
<h:panelGroup rendered="#{menuBean.selectedItemLabel eq menuItem.label}" layout="block">
<h:outputText value="#{menuBean.selectedItemLabel}" />
<ui:include src="#{menuItem.page}" />
</h:panelGroup>
</ui:repeat>
The result is 2 buttons rendered. Whenever I click any button the label inside conditionaly rendered panelGroup appears but included page doesn't. If I change 'menuItem1' var from first ui:repeat it works but it is really unpredictable. For example if I hardcode setSelectedItemLabel parameter to 'page_1' then when I click to button_1 page_1 is displayed but even if I click to button_2 page_2 (!?) is displayed...
You're facing a view build time vs view render time problem. This is essentially the same problem which is already answered in detail in JSTL in JSF2 Facelets... makes sense? In that answer, replace "JSTL" with "ui:include". To the point, the <ui:repeat> runs during view render time, while the <ui:include> has already run during view build time before.
You'll understand that the only solution is to replace the <ui:repeat> by another tag which runs during view build time, such as JSTL <c:forEach>.
Note that I don't guarantee that it will solve the concrete functional requirement which you've in mind. Using JSTL may have undesirable "side effects" (which are however explainable, understandable and workaroundable).
See also:
How to ajax-refresh dynamic include content by navigation menu? (JSF SPA)

How to use component binding in JSF right ? (request-scoped component in session scoped bean)

Mojara 2.1.21
I've updated my question based on comments. I have two situation where a component is bound to server session bean. (Additional links with information: Binding attribute causes duplicate component ID found in the view and https://stackoverflow.com/a/12512672/2692917)
Version 1:
single.xhtml:
<h:outputText value=... binding="#{mysessionbean.out}" />
java:
#SessionScoped #Named public class Mysessionbean {
UIOutput out;
//getter and setter ....
}
Version 2:
template.xhtml:
<h:outputText value=... binding="#{mysessionbean.out}"
view1.xhtml:
<ui:composition template="template.xhtml" />
view2.xhtml:
<ui:composition template="template.xhtml" />
java:
#SessionScoped #Named public class Mysessionbean {
UIOutput out;
//getter and setter ....
}
Version 1 is ok. (At least I've not encounter any errors so far). But in version 2 the duplicate id error is occured if I navigate from one page to another. Why does it happen ?
Is it safe to use (request-scoped) component (in version 1) with session scoped binding ?
Are there another use cases to consider ?
Edit:
Functional requirement 1:
I want to use Primefaces datatable in a view. I need some info from this datatable. (Such as selected row or row index). So binding the datatable helps me to retrieve this info.
Functional requirement 2:
Components binding in composite components. They will be bound to session scoped bean. (And used mainly on one page, but what if I used it on another page ?
Requirements 3
The situation as in "Version 2". Template with primefaces menu and session scoped binding. For this I've used the EL-Binding.
In JSF 2.x, unless you want to manipulate components programmatically (which is at its own also rather fishy), there is no sensible real world use case to bind components to a backing bean. For sure not if they are further not been used in the backing bean itself, or if it are solely their attributes which are been flattened out.
As to the functional requirement of getting the current row of the data table, there are much better ways listed here, How can I pass selected row to commandLink inside dataTable?, for example if your environment supports EL 2.2:
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<h:commandLink value="Foo" action="#{bean.foo(item)}" />
The two last requirements are totally unclear. At least, if you're doing something like:
<x:someComponent binding="#{bean.someComponent}" />
with in bean
someComponent.setSomeAttribute(someAttribute);
someComponent.setOtherAttribute(otherAttribute);
then you should instead be doing
<x:someComponent someAttribute="#{bean.someAttribute}" otherAttribute="#{bean.otherAttribute}" />
Or, if you intend to be able to use the component somewhere else in the view like so
<h:inputText ... required="#{not empty param[bean.save.clientId]}" />
...
<h:commandButton binding="#{bean.save}" ... />
and the instance is further nowhere been used in the bean, then just get rid of the unnecessary property altogether:
<h:inputText ... required="#{not empty param[save.clientId]}" />
...
<h:commandButton binding="#{save}" ... />
If there is really, really no way for some unclear reason, then split all request scoped properties of the session scoped bean out into a separate request scoped bean which you in turn bind to form actions. The session scoped one can just be injected as a #ManagedProperty of the request scoped one.
See also:
Binding attribute causes duplicate component ID found in the view
How does the 'binding' attribute work in JSF? When and how should it be used?
We ran into a similar problem and I just want to share our solution:
Problem:
In a view there was a (extended largely customized) datatable.
<x:dataTable binding="#{bean.someSomeDataTable}" />
After navigating to another page and back we wanted the datatable to have the exact same state. Previously we solved that by binding the datatable to to backing bean. This worked fine with JSPs. With Facelets we could not do that (Duplicate ID errors). So we used the binding, but only saved/restored the state of the datatable component.
public HtmlDataTable getSomeDataTable()
{
HtmlDataTable htmlDataTable = new HtmlDataTable();
if (tableState != null)
htmlDataTable.restoreState(FacesContext.getCurrentInstance(), tableState);
return htmlDataTable;
}
public void setSomeDataTable(HtmlDataTable table)
{
tableState = table.saveState(FacesContext.getCurrentInstance());
}

Primefaces commandButton: f:attribute does not work

Project uses Spring Webflow and JSF (PrimeFaces). I have a p:commandButton with f:attribute
<p:commandButton disabled="#{editGroupMode=='edit'}" action="edit_article_group" actionListener="#{articleGroupManager.setSelectedRow}" ajax="false" value="Edit">
<f:attribute name="selectedIndex" value="${rowIndex}" />
</p:commandButton>
Backend code (Spring injected bean):
#Service("articleGroupManager")
public class ArticleGroupManagerImpl implements ArticleGroupManager{
public void setSelectedRow(ActionEvent event) {
String selectedIndex = (String)event.getComponent().getAttributes().get("selectedIndex");
if (selectedIndex == null) {
return;
}
}
}
The attribute "selectedIndex" is always null. Anybody knows what happened here? Thank you.
The variable name "rowIndex" suggests that you've declared this inside an iterating component, such as <p:dataTable>.
This is then indeed not going to work. There's physically only one JSF component in the component tree which is reused multiple times during generating HTML output. The <f:attribute> is evaluated at the moment when the component is created (which happens only once, long before iteration!), not when the component generates HTML based on the currently iterated row. It would indeed always be null.
There are several ways to achieve your concrete functional requirement anyway. The most sane approach would be to just pass it as method argument:
<p:commandButton value="Edit"
action="edit_article_group"
actionListener="#{articleGroupManager.setSelectedRow(rowIndex)}"
ajax="false" disabled="#{editGroupMode=='edit'}" />
with
public void setSelectedRow(Integer rowIndex) {
// ...
}
See also:
JSTL in JSF2 Facelets... makes sense?
How can I pass selected row to commandLink inside dataTable?
Unrelated to the concrete problem, I'd in this particular case have used just a GET link with a request parameter to make the request idempotent (bookmarkable, re-executable without impact in server side, searchbot-crawlable, etc). See also Communication in JSF 2.0 - Processing GET request parameters.

use multiple form instances jsf 2.0

my jsf appication is designed so that by clicking on a menuitem the corresponding page is displayed in a newly created tab. the pages displayed on tabs have their own form element & backing bean.
normally this works pretty well, but could not find a way how to solve the situation when multiple instances of the same form is used concurrently, eg. more 'add new employee' tabs are opened at the same time.
i try to use a #SessionScoped managed bean with a Map containing instances of the form data (currently only one string for simplicity) like this:
#ManagedBean(name="employeeBean")
#SessionScoped
public class EmployeeBean extends BaseManagedBean implements Serializable{
private Map<String, String> fields = new HashMap<String, String>();
private String formId;
public void newForm(){
this.formId=RandomStringUtils.randomAlphabetic(10);
logger.debug("newForm: formId: " + formId);
this.fields.put(formId, new String());
}
//... etc
}
when i click on a menuitem, a new random formId is generated and new form data holder is added to the fields map.
the jsf page is this:
<html 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:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:p="http://primefaces.prime.com.tr/ui">
<div class="dataContainer clearfix">
<h:form id = "#{employeeBean.formId}">
<h:inputText id="empField1" value="#{employeeBean.fields[employeeBean.formId]}" />
<p:commandLink action="#{employeeBean.action}" value="Action" id="actionLink">
</p:commandLink>
</h:form>
</div>
</html>
the last opened tab instance works perfectly but the old ones do not. if the commandLink is pressed on older tabs the right form is submitted and the getFormId method is called once in the restore view phase, but nothing else is called in my EmployeeBean.
if i use fixed formId not the random #{employeebean.formId} then always the first opened tab's data is submitted. (multiple forms with same id on the page).
i suppose something is wrong with my component tree.
i am using Primefaces's TabView component (based on jquery) and i add new tabs to the tab component in a jquery javascript function.
Can anyone tell me what i am doing wrong? or suggest a better way to solve problem? what is the right approach to handle situtations like this?
thanks a lot in advance
Do you need here a session scoped bean? E.g. do you want to reach bean-content from other pages? If not, than maybe you could simply make your EmployeeBean request scoped. Than you don't need a map inside your employeeBean, and you valuebindings could also be more simple...

Adding JSF 2 composite component at runtime from backing bean

Edited question...
Hello,
I would like to load a .xhtml file of my composite component from a backing bean, and add it to the page dynamically. The name of the .xhtml file comes form a variable.
Ex.:
public MyBean (){
String componentFile = "myCompositeComponent.xhtml"
public String addComponentToPage(){
//how do that?...
return null;
}
}
Thank you!
That's not possible. A composite component is template-based and can only be used in views. Your best bet is to repeat exactly the JSF code which you've originally written in the composite component in the model. Better would be to create a full worthy #FacesComponent class which extends UIComponent, complete with a #FacesRenderer. True, it's a tedious and opaque job, but this way you'll end up with a component which is reuseable in both the view and the model by a single code line.
An -ugly- alternative is to place all possible components in the view and use the rendered attribute.
<my:component1 rendered="#{bean.myComponentType == 'component1'}" />
<my:component2 rendered="#{bean.myComponentType == 'component2'}" />
<my:component3 rendered="#{bean.myComponentType == 'component3'}" />
...
Wrap this if necessary in a Facelets tag file so that it can be hidden away and reused in several places.
I don't understand why do you want to add a composite component from a backing bean. I guess you want to make it visible dynamically in case of an event, but for that there is AJAX reRender.
For example you can do the following:
<h:panelGroup id="composite" rendered="#{myBean.renderComponent}">
<my:compositecomponent/>
</h:panelGroup>
The renderComponent property stores a boolean value. You can switch that value and reRender composite with for e.g. Richfaces's <a4j:commandLink>.
Hope that helps, Daniel

Resources