How to bind JSF component to backing bean property - java

I have a problem with a binding p:commandButton to a property in a backing bean. I've tried to simplify my code to show general idea.
ExampleBean is a backing bean
public class ExampleBean {
public String title;
List<ExampleWrapper> list;
// Getters and setters
}
ExampleWrapper is a POJO
public class Wrapper {
public String name;
public String description;
public CommandButton button;
// Listener which changes button state
// Getters and setters
}
index.xhtml is a main page:
<h:form>
<h:outputText value="Title" />
<p:inpurText value="#{exampleBean.title}"
<ui:include src="list.xhtml">
<ui:param name="bean" value="#{exampleBean}">
</ui:include>
</h:form>
list.xhtml is a fragment I want to be reused in a few places:
<ui:composition ...>
<ui:repeat id="list" var="exampleWrapper" value="#{bean.list}">
<h:outputText value="#{exampleWrapper.name}"/>
<h:outputTextarea value="#{exampleWrapper.description}"/>
<p:commandButton id="button" binding="#{exampleWrapper.button}"
value="Button" />
</ui:composition>
So, I get exception:
javax.el.PropertyNotFoundException: /list.xhtml ... binding="#{exampleWrapper.button}": Target Unreachable, identifier 'exampleWrapper' resolved to null
Without binding attribute everything works and displays fine
Could you explain why and how can I bind button to this POJO property? Any help will be appreciated
I'm using JSF 2.0.2 with Primefaces 3.0.1

The binding (and id) attribute of a JSF UI component is resolved during view build time. The #{exampleWrapper} instance is not available during the view build time. The view build time is that moment when the XHTML file is parsed into a JSF component tree. The #{exampleWrapper} is only available during the view render time. The view render time is the moment when the JSF component tree generates HTML output.
Basically, there's only one <p:commandButton> in the component tree which generates its HTML output multiple times as many as the <ui:repeat> iterates. You need to bind it to the #{bean} instead, or to use JSTL <c:forEach> instead of <ui:repeat>. The JSTL tags runs namely during view build time and the <c:forEach> will thus produce physically multiple JSF UI components. But, more than often, binding components to backing beans is unnecessary in JSF 2.x. Whatever functional requirement you've had in mind for which you thought that this is the solution, it can definitely be solved in a better way.

Related

How to pass a variable value from one xhtml to another xhtml and then to the backing ManagedBean of 2nd xhtml [duplicate]

I'm passing a parameter p1 to another page page.xhtml:
<ui:include src="page.xhtml">
<ui:param name="p1" value="#{someObject}"/>
</ui:include>
Is this possible to evaluate #{p1} inside #PostConstruct method of the backing bean of page.xhtml? Using the following piece of code, #{p1} cannot resolve:
FacesContext currentInstance = FacesContext.getCurrentInstance();
currentInstance.getApplication().evaluateExpressionGet(currentInstance, "#{p1}", String.class);
Why do I need this?
I'm using an xhtml file (say component.xhtml) as a custom UI component. This file has a backing bean from which I should get component data. Since I'm including this xhtml file twice or more in my main JSF page, I want to pass different objects to each of component.xhtml so that my component work with my custom data each time included.
In Mojarra, you can get it as an attribute of the FaceletContext. You can get it in the #PostConstruct of a managed bean which is guaranteed to be referenced/constructed for the first time in the included page (and thus not in the parent page before the <ui:param> is declared in the component tree).
FaceletContext faceletContext = (FaceletContext) FacesContext.getCurrentInstance().getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
Object p1 = faceletContext.getAttribute("p1");
In MyFaces, the whole FaceletContext isn't available in managed beans as it's discarded by end of view build time and this construct would then not work. To be JSF implementation independent, you might want to consider to set it via <c:set scope="request"> instead. It's then available as a request attribute.
As to the concrete functional requirement, consider creating a comoposite component with a backing component. For some examples, see our composite component wiki page and this blog about using multiple input components in a composite component. See also When to use <ui:include>, tag files, composite components and/or custom components?
The param is not available in the #PostConstruct method; you can use the preRenderComponent event to initialize the parameters inside your backing bean; just put it after the ui:composition of the included page, it will be executed before the rendering of the included page itself.
Following the OP example of a passing a p1 parameter to a page.xhtml template
the main page:
<ui:include src="page.xhtml">
<ui:param name="p1" value="#{someObject}"/>
</ui:include>
page.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
...>
<ui:composition>
<f:event listener="#{backingBean.init(p1)}" type="preRenderComponent"/>
...
</ui:composition>
</html>
BackingBean.java:
#ViewScoped
public class BackingBean{
private Object p1;
public void init(Object value){
this.p1=p1;
}
...
}
the event is fired before the render of the ui:composition tag, that is before the render of page.xhtml
This works for me:
<ui:include src="page.xhtml">
<ui:param name="p1" value="#{someObject}"/>
</ui:include>
page.xhtml:
<c:set var="data" value="#{p1}" scope="request"/>
Your bean:
#ViewScoped
public class ManagedBean{
private Object someObject;
public Object getSomeObject(){
if(someObject== null){
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
someObject= request.getAttribute("data");
}
return someObject;
}
public void setSomeObject(Object someObject){
this.someObject = someObject;
}}

JSF datatable and lists [duplicate]

I'm using Primefaces in a JSF 2 application. I have a <p:dataTable>, and instead of selecting rows, I want the user to be able to directly execute various actions on individual rows. For that, I have several <p:commandLink>s in the last column.
My problem: how can I pass a row ID to the action started by the command link so that I know which row to act on? I tried using an <f:attribute>:
<p:dataTable value="#{bean.items}" var="item">
...
<p:column>
<p:commandLink actionListener="#{bean.insert}" value="insert">
<f:attribute name="id" value="#{item.id}" />
</p:commandLink>
</p:column>
</p:dataTable>
But it always yields 0 - apparently the row variable f is not available when the attribute is rendered (it works when I use a fixed value).
Anyone has an alternative solution?
As to the cause, the <f:attribute> is specific to the component itself (populated during view build time), not to the iterated row (populated during view render time).
There are several ways to achieve the requirement.
If your servletcontainer supports a minimum of Servlet 3.0 / EL 2.2, then just pass it as an argument of action/listener method of UICommand component or AjaxBehavior tag. E.g.
<h:commandLink action="#{bean.insert(item.id)}" value="insert" />
In combination with:
public void insert(Long id) {
// ...
}
This only requires that the datamodel is preserved for the form submit request. Best is to put the bean in the view scope by #ViewScoped.
You can even pass the entire item object:
<h:commandLink action="#{bean.insert(item)}" value="insert" />
with:
public void insert(Item item) {
// ...
}
On Servlet 2.5 containers, this is also possible if you supply an EL implementation which supports this, like as JBoss EL. For configuration detail, see this answer.
Use <f:param> in UICommand component. It adds a request parameter.
<h:commandLink action="#{bean.insert}" value="insert">
<f:param name="id" value="#{item.id}" />
</h:commandLink>
If your bean is request scoped, let JSF set it by #ManagedProperty
#ManagedProperty(value="#{param.id}")
private Long id; // +setter
Or if your bean has a broader scope or if you want more fine grained validation/conversion, use <f:viewParam> on the target view, see also f:viewParam vs #ManagedProperty:
<f:viewParam name="id" value="#{bean.id}" required="true" />
Either way, this has the advantage that the datamodel doesn't necessarily need to be preserved for the form submit (for the case that your bean is request scoped).
Use <f:setPropertyActionListener> in UICommand component. The advantage is that this removes the need for accessing the request parameter map when the bean has a broader scope than the request scope.
<h:commandLink action="#{bean.insert}" value="insert">
<f:setPropertyActionListener target="#{bean.id}" value="#{item.id}" />
</h:commandLink>
In combination with
private Long id; // +setter
It'll be just available by property id in action method. This only requires that the datamodel is preserved for the form submit request. Best is to put the bean in the view scope by #ViewScoped.
Bind the datatable value to DataModel<E> instead which in turn wraps the items.
<h:dataTable value="#{bean.model}" var="item">
with
private transient DataModel<Item> model;
public DataModel<Item> getModel() {
if (model == null) {
model = new ListDataModel<Item>(items);
}
return model;
}
(making it transient and lazily instantiating it in the getter is mandatory when you're using this on a view or session scoped bean since DataModel doesn't implement Serializable)
Then you'll be able to access the current row by DataModel#getRowData() without passing anything around (JSF determines the row based on the request parameter name of the clicked command link/button).
public void insert() {
Item item = model.getRowData();
Long id = item.getId();
// ...
}
This also requires that the datamodel is preserved for the form submit request. Best is to put the bean in the view scope by #ViewScoped.
Use Application#evaluateExpressionGet() to programmatically evaluate the current #{item}.
public void insert() {
FacesContext context = FacesContext.getCurrentInstance();
Item item = context.getApplication().evaluateExpressionGet(context, "#{item}", Item.class);
Long id = item.getId();
// ...
}
Which way to choose depends on the functional requirements and whether the one or the other offers more advantages for other purposes. I personally would go ahead with #1 or, when you'd like to support servlet 2.5 containers as well, with #2.
In JSF 1.2 this was done by <f:setPropertyActionListener> (within the command component). In JSF 2.0 (EL 2.2 to be precise, thanks to BalusC) it's possible to do it like this: action="${filterList.insert(f.id)}
In my view page:
<p:dataTable ...>
<p:column>
<p:commandLink actionListener="#{inquirySOController.viewDetail}"
process="#this" update=":mainform:dialog_content"
oncomplete="dlg2.show()">
<h:graphicImage library="images" name="view.png"/>
<f:param name="trxNo" value="#{item.map['trxNo']}"/>
</p:commandLink>
</p:column>
</p:dataTable>
backing bean
public void viewDetail(ActionEvent e) {
String trxNo = getFacesContext().getRequestParameterMap().get("trxNo");
for (DTO item : list) {
if (item.get("trxNo").toString().equals(trxNo)) {
System.out.println(trxNo);
setSelectedItem(item);
break;
}
}
}
Thanks to this site by Mkyong, the only solution that actually worked for us to pass a parameter was this
<h:commandLink action="#{user.editAction}">
<f:param name="myId" value="#{param.id}" />
</h:commandLink>
with
public String editAction() {
Map<String,String> params =
FacesContext.getExternalContext().getRequestParameterMap();
String idString = params.get("myId");
long id = Long.parseLong(idString);
...
}
Technically, that you cannot pass to the method itself directly, but to the JSF request parameter map.

JSF 2.1 validateBean always called before preRenderView event

Im trying to use dynamic validationGroups
<h:inputText id="id" value="#{bean.char}" maxlength="8" alt="#{bean.displayName}">
<f:validateBean
validationGroups="#{bean.validationGroup}" />
</h:inputText>
However the #{bean.validationGroup} is always called before the
<f:event type="preRenderView" listener="#{bean.initView}" />
Is this a bug in Myfaces? I need to have #{bean.validationGroup} called after the prerenderview because preRender loads data from the db and validationGroups will be different. Im using Myfaces 2.1.5 with richfaces 4.1.
This is indeed specified behaviour. The <f:xxx> tags run during view build time. If you like to initialize properties before the view is been built, then you need to do the job in the (post)constructor method of the bean. The pre render view event runs right before the view is to be rendered, but long after the view is been built.
Remove the <f:event> altogether and make the initView a #PostConstruct method instead.
#PostConstruct
public void initView() {
// ...
}
It will run directly after bean's construction and finishing of all dependency injections like #ManagedProperty, #Inject, #EJB and so on.
#ManagedBean
#XScoped --sessionScope,viewScope
Public class Bean{
public void initView(){
if (!FacesContext.getCurrentInstance().isPostback(){
//put initView codes here
}
}
}

JSF property transfer from backing bean A to backing bean B

I'm getting deeper into JSF 2.0 at the moment and lacking a bit of understanding about the "transport" of managed bean properties from one view to the other. I searched a bit but haven't found a really good example, so if anyone could point me to a tutorial or explain the things a little bit I'd really grateful.
So here is my scenario:
I'm developing a small playground calendar application. The first view select.xhtml contains the calendar selector, where the user can pick a specific date:
<html>
...
<h:form>
<!-- Calendar selector from primefaces -->
<p:calendar value="#{calendarSelect.date}" mode="inline" navigator="true" />
<p:commandButton value="Show entries for date" action="day" />
...
My corresponding backing bean looks like this:
#ManagedBean(name="calendarSelect")
#RequestScoped
public class CalendarSelectComponent {
private Date date = null;
... // Getters and setters
Now when I submit the form from select.xhtml I'm forwarded to day.xhtml
<html>
...
<h:form>
The current day ist:
<h:outputText value="#{calendarEdit.date}">
<f:convertDateTime pattern="dd.MM.yyyy" />
</h:outputText>
The backing bean now looks like this:
#ManagedBean(name="calendarEdit")
#ViewScoped
public class CalendarEditComponent implements Serializable {
private Date date = null;
private CalendarEntryBean currentEntry = null;
private List<CalendarEntryBean> allEntries = null;
....
I am now trying to solve the problem: How do I transfer the date parameter from the selector to the editor?
I've tried a number of options, one was this:
<p:commandButton value="Show entries for date" action="day" />
<f:setPropertyActionListener target="#{calendarEdit.date}" value="#{calendarSelect.date}" />
</p:commandButton>
A debugger shows, that indeed, the date property of the calendarEdit is populated with the value from calendarSelect, but since day.xhtml is a new view, a new CalendarEditComponent backing bean is being created and not the one I've populated with the date from the selector in the select view.
I've read that one solution would be to create a SessionScoped backing bean that does retain all it's values. But this is not the way I think it's supposed to work, because I don't really need the information in the session, I simply want it to "travel" from A to B. Another downside with the session based approach is that I can only use one selector and one editor per session - which I think isn't acceptible if you think of multi window browsing and so on.
I really don't think I'm the first one encountering such a scenario and I'm sure that JSF provides an elegant solution for this but I haven't been able to find that solution.
So once again, if anyone knows how to approach this - I'm listening! ;-)
The <f:setPropertyActionListener> is executed during invoke action phase of the form submit. So it expects that the value is still there at that point. But since your select bean is request scoped, it isn't there during form submit anymore. You want instead to pass a request parameter which get inlined in the output during render response. You can do this with <f:param>.
<p:commandButton value="Show entries for date" action="day" />
<f:param name="date" value="#{calendarSelect.dateAsString}" />
</p:commandButton>
It'll be available as request parameter (note that it only understands Strings, due to the nature of HTTP). You could let JSF set request parameters as managed properties, but since your edit bean is view scoped, this isn't possible with #ManagedProperty. You've got to gather it yourself by ExternalContext.
String dateAsString = externalContext.getRequestParameterMap().get("date");
True, that's clumsy. I would just have used the same bean and view for this and toggle visibility of select/edit forms by rendered attribute. The edit view is after all not directly openable/bookmarkable by a simple GET, isn't it? ;)

JSF2 DataBinding Problem

I have a little issue regarding submit of forms in jsf 2:
In my webapp I got a function that updates entities in my db. This function gets the relative data out of a managed bean.
So, my issue is that changes in my view are not passed to the managedBean. To make that clear for you, here an example:
public String updateProject() {
projectService.updateProject(projectData.getProjectDTO());
return ("overview.xhtml");
}
prjectData is my ManagedBean. This one doesn't work! No updates are been made.
public String deleteProject() {
projectData.getProjectDTO().setDeleted(true);
projectService.updateProject(projectData.getProjectDTO());
return ("overview.xhtml");
}
Here, when I change a value by code it works! So I guess my values out of the view are not passed to my managedBean.
Where could be a mistake? Is there maybe an action I have to invoke to make the data pass my view to the managedBean?
Answer to Gabor's comment:
My page looks like:
<h:form>
<h:commandLink action="#{controller.updateProject}" value="Edit" />
<h:outputLabel for="title" value="Titel" />
<h:inputText id="title" value="#{projectData.projectDTO.title}" />
</h:form>
If I change the title here and press update nothing happens ;-)
My Controller looks like:
#ManagedBean
#RequestScoped
public class Controller {
#ManagedProperty(value = "#{projectData}")
private ProjectData projectData;
...
For unknown reason my debug mode in eclipse doesn't work anymore it ignores my breakpoints all the time. I gonna fix that and then I'll check about the instances. Sry -.-
Either projectData or projectDTO is not the right instance as you expect it to be. It's a completely different instance. Aren't you eagerly recreating/overriding beans? Don't you have multiple beans in the scope? Shouldn't it for example be #{controller.projectData.projectDTO.title}? Shouldn't the projectData instance in the controller be a managed property?
Is your projectData bean also RequestScoped? Try to change to ViewScoped. RequestScoped beans are recreated for each request, also ajax request. And what is scope of projectService?

Categories

Resources