JSF bookmarking problem - jsf

I have a h:datatable that display employees data.
I want the user when click the employee name to navigate to a new page which URL looks like
employees?id=<some id>
I've tried to combine JSP EL with JSF EL, but no way out.

If you're not on JSF 2.0 yet, then you can just make use of h:outputLink in combination with <f:param>, #{param} and faces-config.xml.
Basic table example:
<h:dataTable value="#{bean.employees}" var="employee">
<h:column>
<h:outputLink value="employees.jsf">
<f:param name="id" value="#{employee.id}" />
<h:outputText value="View employee #{employee.name}" />
</h:outputLink>
</h:column>
</h:dataTable>
Basic faces-config.xml example:
<managed-bean>
<managed-bean-name>employeeManager</managed-bean-name>
<managed-bean-class>com.example.EmployeeManager</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>id</property-name>
<value>#{param.id}</value>
</managed-property>
</managed-bean>
Basic com.example.EmployeeManager example:
public class EmployeeManager {
private Long id;
private Employee employee;
#PostConstruct
public void init() {
this.employee = employeeDAO.find(this.id);
}
}
The #PostConstuct annotated methods will be invoked after bean construction and all of injection and managed property setting. Also see this article for more info and examples.

There are two possible solutions I can think of:
Use JSF 2 (part of Java EE 6)
If you are stuck in JSF 1.x, use PrettyFaces.
If it's possible to switch to a Java EE 6 server, I highly recommend option number 1.
Edit: There are 2 tags that were added in JSF 2: <h:link /> and <h:button />. These use GET instead of POST. Also, look into <f:viewparam />. On top of this, there are many other wonderful additions in JSF 2. For a brief overview, see this article.

Related

Why is this ViewScoped managed bean not working and how can I make it work?

This is the list page I have:
<h:dataTable value="#{actorSearchBacking.all}" var="actor">
<h:column>
<f:facet name="header">
First Name
</f:facet>
#{actor.firstname}
</h:column>
<h:column>
<f:facet name="header">
Last Name
</f:facet>
#{actor.lastname}
</h:column>
<h:column>
<h:form>
<h:commandButton value="Update Actor" action="pocdetail">
<f:setPropertyActionListener target="#{actorFormBacking.stupidActor}" value="#{actor}"/>
</h:commandButton>
</h:form>
</h:column>
</h:dataTable>
which looks something like this in my local environment:
This is pocdetail.xhtml which is the action of Update Actor button:
<h:body>
<h:form id="updateActorForm"
prependId="false">
<h:inputText id="firstname" value="#{actorFormBacking.stupidActor.firstname}"/>
<h:inputText id="lastname" value="#{actorFormBacking.stupidActor.lastname}"/>
<h:commandButton id="updateActorButton"
value="Update Actor!"
action="#{actorFormBacking.updateActor()}"/>
</h:form>
</h:body>
And finally ActorFormBacking is as follows:
#ManagedBean
#ViewScoped
public class ActorFormBacking implements Serializable {
private Actor stupidActor;
public Actor getStupidActor() {
return stupidActor;
}
public void setStupidActor(Actor stupidActor) {
this.stupidActor = stupidActor;
}
}
When I debug the application, I see that setStupidActor is called and property stupidActor is set, but then when getter is called, it is again null.
Since this is a ViewScoped bean, I am expecting the stupidActor not to be null and I expect to see the pocdetail.xhtml page to be filled with values, but all I see is empty input texts since stupidActor is null.
What is it that I am missing? Why is the ViewScoped bean created again and the property is null?
Btw, I am using the annotations from the packages:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
It appears that you're navigating from one view to another view. In other words, you destroy the current view and create a new view. Logically, the view scope will also get destroyed and newly created, including all view scoped managed beans. That the view scoped managed bean happens to be referenced by both views doesn't change this behavior.
A view scoped bean lives as long as the view itself. Like as that a request scoped bean lives as long as the request itself and so on. In order to have a better understanding of the lifetime of various scopes in JSF (and CDI), head to this Q&A: How to choose the right bean scope?
The functional requirement is however understood. You want separate master-detail pages and pass the selected item from the master page to the detail page for editing. There are several ways to achieve this:
The canonical way is to just use a bookmarkable GET link instead of an unbookmarkable POST link. Replace the below piece
<h:form>
<h:commandButton value="Update Actor" action="pocdetail">
<f:setPropertyActionListener target="#{actorFormBacking.stupidActor}" value="#{actor}"/>
</h:commandButton>
</h:form>
by this
<h:link value="Update Actor" outcome="pocdetail">
<f:param name="stupidActor" value="#{actor.id}" />
</h:link>
and in the detail page, obtain the Actor by its identifier which is passed-in as query string parameter. This is fleshed out in detail in this Q&A: Creating master-detail pages for entities, how to link them and which bean scope to choose. A #FacesConverter(forClass) is very useful here.
In case you want to stick to POST for some reason, then your best bet is storing it in the request scope.
FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("stupidActor", stupidActor);
and retrieve it in the #PostConstruct of the very same bean
stupidActor = (Actor) FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("stupidActor");
If you happen to use CDI, or are open to (which I strongly recommend though, JSF managed beans are already deprecated in JSF 2.3.0-m06, see also Backing beans (#ManagedBean) or CDI Beans (#Named)?), then consider using MyFaces CODI's #ViewAccessScoped. Beans with this scope will live as long as all postbacked views explicitly reference the bean. Once you navigate out with a GET, or when the navigated view doesn't anywhere reference that bean, then it will get destroyed.
#Named
#ViewAccessScoped
public class ActorFormBacking implements Serializable {}
Merge the both views into a single view with conditionally rendered master-detail sections. You can find a kickoff example in this Q&A: Recommended JSF 2.0 CRUD frameworks. Or if you happen to use PrimeFaces, How to show details of current row from p:dataTable in a p:dialog and update after save.

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());
}

<h:commandLink> not working inside a <h:dataTable>

I will try to explain myself:
I'm working on a JSF project using java, JSF 2.0 and RichFaces 4.2.1.
When I access my jsf it just loads a search filter and a commandLink. The commandLink will launch a method in my backingBean to load data that it will be displayed in a dataTable.
<h:commandLink id="btnRecords">
<f:ajax render="myCompAjax" event="click" listener="#{myBean.loadRecords}" />
<h:graphicImage value="img/ico_new.gif" alt="#{bundle['button.search']}" />
</h:commandLink>
The datatable is not visible at first, but once you click on the commandLink a flag in the backingBean will change and the table displays with data I just loaded.
<a4j:outputPanel ajaxRendered="true" id="myCompAjax">
<h:dataTable id="recordsTable" value="#{myBean.records}"
var="item" rendered="#{myBean.flagShowTable}">
<h:column headerClass="thPijama" >
<f:facet name="header">
<table><tr class="thPijama"><td></td></tr></table>
</f:facet>
<h:commandLink action="#{myBean.goNextPage}">
<h:outputText value="Go Next Page" />
<h:inputHidden value="#{item}" />
</h:commandLink>
</h:column>
</h:dataTable>
</a4j:outputPanel>
Problem is the commandLink action inside of the dataTable isn't working at all. I just want to navigate to another jsf. In fact, what it does is hiding the dataTable and leaving the filter unchanged. The action method remains unreachable.
Of course, it works if I set the same commandLink outside the dataTable.
I cannot use Session Scope Beans because the people I work for don't approve it.
Can anyone help me?
Thanks for the hint.
I cannot use Session Scope Beans because the people I work for don't approve it.
Are you implying that placing the bean in the session scope instead of the request scope actually solved the problem? If so, then just put the bean in the view scope.
#ManagedBean
#ViewScoped
public class MyBean implements Serializable {
// ...
}
This way the bean will live as long as you're interacting with the same view by ajax requests. The bean is not been shared in other browser tabs/windows in the same session (which is among the architects indeed the major reason to forbid its use in case of simple views).
See also:
How to choose the right bean scope?
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 4 applies to you

Passing a parameter with h:commandButton

I have a a4j:commandButton which is supposed to redirect me to an appropriate "Edit" page based on an Id, which I wanted to pass as a parameter, something like this:
<h:commandButton action="/details.jsf?faces-redirect=true" value="details">
<f:attribute name="id" value="#{bean.id}" />
</h:commandButton>
The problem is, it doesn't work. I also tried replacing f:attribute with "f:param name="id" value="#{bean.id}" ", but it also failed. The only thing I got to work is an outputLink:
<h:outputLink value="/details.jsf">
link
<f:param name="id" value="#{bean.id}" />
</h:outputLink>
But I'm not really happy with a link, so is there a way to make the commandButton work?
Oh and I also have a bean which is supposed to get that "id" after the redirect:
#PostConstruct
public void init(){
id= resolve("id");
}
Have a look at this article about communication in JSF, by BalusC
f:param only works with h:commandLink and h:outputLink.
You can use an input hidden:
<h:form>
<h:commandButton action="/details.jsf?faces-redirect=true" value="details"/>
<input type="hidden" name="id" value="#{bean.id}" />
</h:form>
And then in your faces-config, I guess is request scoped. If you use the annotations of JSF2, just translate this to the proper annotations.
<managed-bean>
<managed-bean-name>bean</managed-bean-name>
<managed-bean-class>mypackage.Bean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>id</property-name>
<value>#{param.id}</value>
</managed-property>
</managed-bean>
You need obviously to have getters and setters for that field in the backing bean.
or try to "paint" the link as a button through CSS.
Unless my JSF is extremely rusty, the action attribute on a command button or command link is used to specify the outcome string defined in your faces-config-nav file, or it should point to a method on the bean which will return an outcome (or redirect/whatever).
In your case, if you want to redirect to another page... you should define that in your config file, as a navigation link (with redirect if necessary). Then in your action button you should have something like
<h:commandButton action="showDetails" value="details">
...
<navigation-case>
<from-outcome>showDetails</from-outcome>
<to-view-id>/details.jsf?faces-redirect=true</to-view-id>
</navigation-case>
As an aside, the <f:atribute> tag will work, but it will only set the attribute onto the component. So if you got a hold of the command button in your bean, you could be able to get the attribute value by name. To pass a request param, use the hidden field technique like pakore mentioned

How to pass url parameters to JSF?

I haven't managed to find a way to pass parameters to JSF pages through URL parameters.
http://www.example.com/jsfApp.jsp?param1=value1&param2=value2
Could someone point me at the right direction with this?
As you're using JSPs, I'll assume that you're using JSF 1.x.
To create a link with query parameters, use h:outputLink with f:param:
<h:outputLink value="page.jsf">
<f:param name="param1" value="value1" />
<f:param name="param2" value="value2" />
</h:outputLink>
The value can be set dynamically with help of EL.
To set them in the managed bean automagically, you need to define each as managed-property in faces-config.xml:
<managed-bean>
<managed-bean-name>bean</managed-bean-name>
<managed-bean-class>com.example.Bean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>param1</property-name>
<value>#{param.param1}</value>
</managed-property>
<managed-property>
<property-name>param2</property-name>
<value>#{param.param2}</value>
</managed-property>
</managed-bean>
The imlicit EL variable #{param} refers to the request parameter map as you know it from the Servlet API. The bean should of course already have both the param1 and param2 properties with the appropriate getters/setters definied.
If you'd like to execute some logic directly after they are been set, make use of the #PostConstruct annotation:
#PostConstruct
public void init() {
doSomethingWith(param1, param2);
}
For more hints about passing parameters and that kind of stuff around in JSF, you may find this article useful.
The JSF 2.x approach would be using either #ManagedProperty in the backing bean class, or <f:viewParam> in the target view. See also this question: ViewParam vs #ManagedProperty(value = "#{param.id}")

Resources