JSF how add a control on the first url - jsf

I have to implement a new feature in my existing JSF application.
As it is now, there is a feature for searching a objects. The normal flow is: fill in some form parameters and see the detailed object page after submitting the form.
Now I have to find a way to go to the detailed object page via a link which arrives through an email.
In the link there are some parameters, useful to find the object, but if the object doesn't exist I would to forward the user to a courtesy page.
How could I manage this thing?
thank you very much

Do the job in constructor or #PostConstruct method of the bean which is associated with the view and use the rendered attribute to render page fragment/include conditionally.
#PostConstruct
public void init() {
someObject = someDAO.find(someParam);
}
with
<h:panelGroup rendered="#{bean.someObject != null}">
Found
</h:panelGroup>
<h:panelGroup rendered="#{bean.someObject == null}">
Not gound
</h:panelGroup>
Or use ExternalContext#redirect() to redirect to another view.
#PostConstruct
public void init() {
someObject = someDAO.find(someParam);
if (someObject == null) {
FacesContext.getCurrentInstance().getExternalContext().redirect("notfound.jsf");
}
}

Related

JSF Request Scoped Bean not displaying data in page

I'm experimenting with JSF scopes, and have some issues when using a session scoped bean within a request scoped bean.
The basic workflow is that the user would click a View button on an item from the home page, which then calls my code to load & display that item's information.
Here's my UPDATED code:
#ManagedBean(name="itemViewBean")
#RequestScoped
class ItemViewBean {
#ManagedProperty("#{itemBean}")
private ItemBean itemBean;
private ItemViewObject itemViewObject;
private int itemId;
public void init() {
itemViewObject = itemBean.readItem(itemId);
}
public String readItem(int itemId) {
// itemViewObject = itemBean.readItem(itemId); // moved to init();
return "/pages/viewItem.xhtml?faces-redirect=true";
}
public ItemViewObject getItemViewObject() {
return itemViewObject;
}
// getters & setters as needed
}
#ManagedBean(name="itemBean")
#SessionScoped
class ItemBean {
public ItemViewObject readItem(int itemId) {
// hardcoded creating a ItemViewObject for now.
// eventually would be loaded from the database.
....
}
}
My UPDATED view page then has things like:
<!-- added the metadata -->
<f:metadata>
<f:viewParam name="id" value="#{itemViewBean.itemId}" />
<f:event listener="#{itemViewBean.init}" type="preRenderView" />
</f:metadata>
<!-- same as before -->
<h:outputText value="#{itemViewBean.itemViewObject.description}" />
If my viewBean is request scoped (or view scoped), I get empty data on the view page. If the viewBean is session scoped, things work. And I'm not understanding why?
From what I see in my debugger, readItem(itemId) is called (from the home page when clicking a view button), but when the view page itself calls the getItemViewObject(), the itemViewObject is null.
What am I doing wrong?
UPDATE
I forgot to mention earlier how my home page was calling readItem method, and that was through a command button:
<h:commandButton class="btn btn-mini firefoxBtnMiniCorrection"
value="View"
action="#{itemViewBean.readItem(b.itemId)}"/>
Each item listed in the home page has its own View button.
Also forgot to mention that both the home page and my view page are using JSF Templates. I don't know if that matters.
From the comments below which people have made, I came up with the code changes above. And things work now. Using either request scope or view scope with ItemViewBean works now.
And I am surprised this worked! I'm not quite certain I fully understand why it works.
Are my changes the correct way to do things? Or is there a better way?
Also, I'm using JSF 2.1.
Update 2
It doesn't work. The scoping works, but I discovered that the itemId in the viewParam is always null. Why?
itemViewObject is private in a RequestScoped bean. After readItem() got a value for itemViewObject, this value will be forgotten after this request and will be null at the next request (`#RequestScoped').

How to safely init a ViewScoped bean with URL GET request parameters? [duplicate]

This question already has answers here:
How do I process GET query string URL parameters in backing bean on page load?
(4 answers)
Closed 7 years ago.
I have a few managed bean (ViewScoped) that are currently initialized with data in the session. I would like to initialize them with a URL GET parameter so I can provide URLs with the entity ID I want to display in my view. Something like displayClient.xhtml?entityId=123.
Right now I am thinking of something like this in the getter of the view main entity :
public clientModel getclientM() {
if (this.clientM == null) {
// TODO: Check for empty, non-integer or garbage parameters...
// Anything exists to "sanitize" URL parameters?
int entityId = Integer.parseInt(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("entityId"));
// I guess I should check here if the logged user is authorized to
// load client entity with this entityId... anything else to check?
this.clientM = this.clientS.find(entityId);
}
return this.clientM;
}
Any hint or suggestion of best practices would be greatly appreciated.
I'd think something along these lines are best practice:
displayclient.xhtml:
<f:metadata>
<f:viewParam name=“entityId”
value="#{bean.clientM}”
required="true"
converter=“clientModelConverter”
converterMessage="Bad request. Unknown ClientModel.”
requiredMessage="Bad request. Please use a link from within the system.">
</f:viewParam>
</f:metadata>
Converter:
#ManagedBean
#RequestScoped
public class ClientModelConverter implements Converter {
#EJB
private ClientService clientService;
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
// TODO: check if value is instanceof ClientModel
return String.valueOf(((ClientModel) value).getId());
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
// TODO: catch NumberFormatException and throw ConverterException
return clientService.find(Integer.valueOf(value));
}
}
Call the page with for example:
<h:link value=“Display” outcome="displayClient">
<f:param name=“entityId" value=“#{…}” />
</h:link>
or just a raw url for example displayClient.xhtml?entityId=123.
Heavily inspired by
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for? and
JSF 2.0 view parameters to pass objects.
Store entityId in session, for example SessionScoped Bean
In your View Scoped managed beans, add #PostConstruct method, where you will get entityId from session and populate data with this
I did something similar, for the same exact reason : Providing an external link to a jsf page.
In your ViewScoped bean, have a #PostConstruct method to force a fail-safe scan for the Get Param
#PostConstruct
public void scanEntityId(){
int entityId = 0; // or some other default value
try{
// Try to fetch entityId from url with GET
int entityId = Integer.getInteger(FacesContext.getExternalContext().getRequestParameterMap().get("entityId") );
}catch(Exception e){
// Did not find anything from GET
}
// TODO: do stuff using the entityId's value. e.g.:
if(entityId >0){
this.clientM = this.clientS.find(entityId);
}
}
Just make sure to handle the cases where the entityId var is not found in the Get params
If you want to link to that page from another xhtml page of the same app, you can use the f:param
<h:link value="Go in a page that uses thatViewScoped Bean"
outcome="#{thatViewScopedBean.takeMeToThatPage}" >
<f:param name="entityId" value="#{somebean.somevar.entityId}" />
</h:link>
A nice tutorial can also be found here
You might also like to see this answer, and this article to see more options and get a more clear view.

Single page applications with ajax [duplicate]

This question already has answers here:
How to ajax-refresh dynamic include content by navigation menu? (JSF SPA)
(3 answers)
Closed 1 year ago.
I'm relatively new to JSF and trying to learn how current JSF 2 applications are designed. I've seen reference to single page applications that use ajax. Can someone fill me in on some of the techniques used and / or point me to a model or book? The books I've seen (JSF Complete Reference etc.) are good for basic tech issues but I can't find a source for current design techniques.
Thanks
Dave
In order to implement your Single Page Application, you should state which piece of your page should be rendered. This can be accomplished making use of a boolean flag such as create, edit, list, and so on. For instance, see the following (Just relevant code)
<h:body>
<h:form rendered="#{userController.stateManager.create}">
<h:panelGroup rendered="#{not empty facesContext.messageList or userController.stateManager.failure}">
<!--render error message right here-->
</h:panelGroup>
<div>
<label>#{messages['br.com.spa.domain.model.User.name']}</label>
<h:inputText value="#{user.name}"/>
</div>
<h:commandButton action="#{userController.create}">
<f:ajax execute="#form" render="#all"/>
<f:actionListener type="br.com.spa.web.faces.listener.StateManagerActionListener" />
<f:setPropertyActionListener target="#{userController.stateManager.create}" value="true"/>
<f:setPropertyActionListener target="#{userController.user}" value="#{user}" />
</h:commandButton>
</form>
</h:body>
Notice that our form will be rendered when a flag create is true - See second line above. To wrap our flags, we create a classe named StateManager as follows
/**
* I am using lombok, which takes care of generating our getters and setters. For more info, please refer http://projectlombok.org/features/index.html
*/
#Setter #Getter
public class StateManager {
private boolean create;
private boolean edit;
private boolean list;
}
Now, because we are using only a single page, we should use a ViewScoped managed bean, which keep our managed bean scoped active as long as you are on the same view - Is it a single page application, right ? So, no navigation. With this in mind, let's create our managed bean.
#ManagedBean
#ViewScoped
public class UserController implements StateManagerAwareManagedBean {
private #Inject UserService service;
private #Getter #Setter stateManager = new StateManager();
private #Getter #Setter List<User> userList = new ArrayList<User>();
private #Getter #Setter User user;
#PostConstruct
public void initialize() {
list();
}
public void create() {
service.persist(user);
stateManager.setCreate(false);
stateManager.setList(true);
stateManager.setSuccess(true);
}
public void edit() {
service.merge(user);
stateManager.setEdit(false);
stateManager.setList(true);
stateManager.setSuccess(true);
}
public void list() {
userList = service.list();
stateManager.setList(true);
}
}
For each action method, we define which piece of our page should be rendered. For instance, consider that our form was processed, covering all of JSF lyfecycle, which implies that their values was successfully converted and validated, and our action method invoked. By using as example our create action method - see above -, we set its create flag as false because our form was converted and validated, so we do not need to show it again (Unless you want). Furthermore, we set both list and success flag as true, which indicates that the list of our page should be rendered and our form was successfully processed - You could use this flag to show something like "User created" such as bellow
<h:panelGroup rendered="#{userController.stateManager.success}">
#{messages['default.created.message']}
</h:panelGroup>
Now, let's discuss which piece of our page should be rendered when it is called for the first time. Maybe you do not know but a void method annotated with #PostConstruct will be called first. So we define which piece of our page should be rendered. In our example, we call list method, which sets its list flag as true and populate a backing list.
#PostConstruct
public void initialize() {
list();
}
Finally, let's review the following order nested within h:commandButton
<h:commandButton action="#{userController.create}">
<f:ajax execute="#form" render="#all"/>
<f:actionListener type="br.com.spa.web.faces.listener.StateManagerActionListener" />
<f:setPropertyActionListener target="#{userController.stateManager.create}" value="true"/>
<f:setPropertyActionListener target="#{userController.user}" value="#{user}" />
</h:commandButton>
First of all, you should call an ActionListener - here called StateManagerActionListener - which takes care of resetting any StateManager - code bellow. It must be called first before any other setPropertyActionListener designed to control any flag because the order defined within h:commandButton is the order in which they will be called. keep this in mind.
public class StateManagerActionListener implements ActionListener {
public void processAction(ActionEvent e) throws AbortProcessingException {
Map<String,Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
for(Map.Entry<String,Object> entry: viewMap.entrySet()) {
if(entry.getValue() instanceof StateManagerAwareManagedBean) {
((StateManagerAwareManagedBean) entry.getValue()).setStateManager(new StateManager());
}
}
}
}
StateManagerAwareManagedBean - used in our ViewScoped Managed bean -, which allows that we reset any StateManager of any ManagedBean instead of resetting one by one in our ActionListener, is defined as follows
public interface StateManagerAwareManagedBean {
StateManager getStateManager();
void setStateManager(StateManager stateManager);
}
Second, after defining our ActionListener, we use a setPropertyActionListener which set the flag which controls the enclosing piece of the view as true. It is needed because our form is supposed to be not converted and validated. So, in our action method, we set this flag as false as discussed before.
A couple of notes
User is marked as a RequestScoped ManagedBean so that it can not be injected into a ViewScoped one using a ManagedProperty because its scope is shother. To overcome this issue, i set its value by using a <f:setPropertyActionListener target="#{userController.user}" value="#{user}"> - See our form
Our example use JEE features which need a proper Application Server. For more info, refer http://docs.oracle.com/javaee/6/tutorial/doc/
ManagedBean can play different roles such as a Controller, DTO and so on. When it play a role of a Controller, i prefer suffix its name with Controller. For more info, refer http://java.dzone.com/articles/making-distinctions-between

c:set for bean properties

I'm looking for some piece of code for setting a property in a JSF managed bean. My first idea was something like that:
<c:set var="#{loginBean.device}" value="mobil"></c:set>
That means I want to set the attribute device to the value "mobil" without a button have to been clicked.
Yes, you can use c:set for this purpose.
<c:set value="mobil" target="#{loginBean}" property="device" />
Doc: http://docs.oracle.com/cd/E17802_01/j2ee/javaee/javaserverfaces/2.0/docs/pdldocs/facelets/c/set.html
However, setting a static value rarely makes sense. You might consider to set a default value directly in your managed bean class. Also in terms of maintainability since you can handle constants better in the Java code than in the view layer.
I think you want the JSF tag child tag setPropertyActionListener. You can set this as a child tag in any ActionComponent.
<h:anyActionComponent id="component1">
<f:setPropertyActionListener target="#{loginBean.device}" value="mobil" />
</h:anyActionComponent>
UPDATE:
I originally misunderstood the users problem. They have a page, and they want a property to be set when the page loads. There is a couple ways to do this, but both are a little different. If you want to set a property to a value after every postback then you can use the #PostConstruct annotation on a ManagedBean method.
#PostConstruct
public void initializeStuff() {
this.device = "mobil";
}
Now if I have a ViewScoped or SessionScope bean that needs to be initialized with a default value just once when the page loads then you can set a phase lifecycle event that will run after every postback and check to see if the page should be initialized or not.
mah.xhmtl:
<f:event listener="#{loginBean.initialize()}" type="preRenderView" />
LoginBean:
public void initialize() {
if (this.device == null)
this.device = "mobil";
}
I am not able to Comment: If you need the value to be ready on page on load, you could use Managed Bean to directly initialize value or use its constructor or #PostConstruct to do the same.
#ManagedBean
#ResquestScoped
public class LoginBean {
private String device = "some value";
//Using Constructor
public LoginBean() {
device = getvalueFromSomewhere();
}
//Using PostConstruct
#PostConstruct
public void init() {
device = getvalueFromSomewhere();
}
}
Instead of setting the value in the xhtml file you can set via another ManagedBean. For instance if you have managedBean1 which manages page1.xhtml and managedBean2 which manages page2.xhtml. If page1.xhtml includes page2.xhtml like:
<ui:include src="page2.xhtml"/>
in managedBean1 you can have at the top
#ManagedProperty(value = "#{managedBean2}")
private ManagedBean2 managedBean2;
and in the PostConstruct
#PostConstruct
public void construct() {
managedBean2.setProperty(...);
}
worked for me anyway...

Unable to retrieve the value of <h:selectBooleanCheckbox> inside my managed bean's action method

JSF view code:
<f:view>
<h:form>
<h:panelGrid>
<h:inputText id="key" value="#{myManagedBean.key}"/>
<h:selectBooleanCheckbox id="rerun" value="#{myManagedBean.rerun}" rendered="#{myManagedBean.displayRerun}"/>
<h:commandButton id="check" action="#{myManagedBean.check}"/>
</h:panelGrid>
</h:form>
<f:view>
JSF model code:
public class MyManagedBean {
private boolean displayRerun;
public void setDisplayRerun(boolean aDisplayRerun) {
this.displayRerun = aDisplayRerun }
public boolean getDisplayRerun() {
return this.displayRerun;
}
private String key;
public void setKey(String aKey) {
this.key = aKey
}
public String getKey() {
return this.key;
}
private boolean rerun;
public void setRerun(boolean arerun) {
this.rerun = arerun
}
public boolean getRerun() {
return this.rerun;
}
public String check() {
//do data validation
setDisplayRerun(true);
System.out.println(getRerun());
}
}
This always prints false regardless of whether the checkbox is checked or not.
Additional Information on my requirement:
Nick/BalusC, my managed bean is of request scope. It is indeed simplified code snippet that I presented. My page has couple of user input controls along with a command button. On submit of command button, I call action method of backing bean, in which I do data validation (in this case I lookup database and see if the inputs are already registered.) If already registered, I come back to the same page, this is when I display the singleBooleanCheckBox for the user to select and hit the command button again.
I am toggling the display of the checkbox based on a managedbean property (a boolean flag set during data validation).
When I re-submit the page with checkbox checked, I do not receive this data.
For further verification, I replace the selectBooleanCheckbox, with a command button with similar behavior (basically do not render it initially, but only show it on data validation). I mapped its #action to my managedbean's action method. To my surprise, when I hit the button, the action method is not executed. Instead, the page is refreshed like in a "immediate" scenario or a redirect.
I have been struggling on this for almost 6 hrs. Appreciate your experienced insights.
Thanks.
So, you've actually a rendered attribute on the checkbox (that was not present in your initial question) and the bean is request scoped (it would have worked when it was session scoped). The submitted checkbox value will not be gathered during apply request values phase when this attribtue evaluates false at that point.
You basically need to retain the condition responsible for the rendered attribute in the subsequent request as well. This can be done in several ways: putting bean in session scope, using Tomahawk's t:saveState or h:inputHidden with a bean binding. Each is outlined in detail in this answer.

Resources