How to trigger destruction of viewscoped bean? - jsf-2

I have a #ViewScoped-annotated managedbean whose #PostContruct-method fetches a list from database to be displayed in a table in the view.
Now when I delete an item I want the changes to be seen in the view.
To keep this dynamic and reusable I only want to delete from database (not manually from list). So I need to destroy/recreate the bean I suppose. Now I do this by navigating to the same view. But the way I do is not reusable.
Can I just destroy the bean manually or navigate to the same view without explicitly navigating to THAT specific view (reusability)?
I am using JSF 2.1

You're already on the right track. viewMap is just like any other map; You can remove a ViewScoped bean by name. Please excuse the atrocious chaining:
FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove("yourBean");

One solution I found is to destroy the bean by
FacesContext.getCurrentInstance().getViewRoot().getViewMap().clear();
I am not sure if this is the way to go because it simply destroys every viewscoped bean. It's not that bad in this case, but doesn't feel clean.
I appreciate any thought on that or alternative solutions.

When you return a non null value inside a method from an action attribute the Bean gets recreated.
index.xhtml
...
<h:commandButton value="delete" action="bean.delete" />
...
Bean.class
...
public String delete() {
// do operations
return "index.xhtml?faces-redirect=true";
}
...

Related

JSF PrimeFaces ViewScope without calling init()

I have encounter an issue using Primefaces dataTable that is the jsf will call my managed bean init() which will do a search from database.
In my jsf, user are able to perform another search which pass an argument in String.
<p:commandButton id="btnChild" type="Submit" icon="ui-icon-plus" styleClass="action-buttons" value="Child" update=":frmSysMenu:messages dtSysMenu" ajax="false" action="#{Controller.doParent('C')}" process="dtSysMenu" />
my managed bean are able to execute the doParent(String) and will go back to the search screen again but once my screen is loaded, it will call init() which:
#PostConstruct
#Override
public void init(){
try {
doSearch(nodeValue,"root");
setParentNode(nodeValue);
} catch (Exception e) {
addErrorMessage(e.getMessage());
e.printStackTrace();
Messages.addGlobalError(e.getMessage());
LOG.error(e.toString(), e);
}
}
and it will gone back to the first query.
is there any other way that I can do?
Does RequestScoped help?
From the specs (or somewhere else, OP did not mention it)
#ViewScoped
A bean in this scope lives as long as you're interacting with the same JSF view in the browser window/tab. It get
created upon a HTTP request and get destroyed once you postback to a
different view. It doesn't immediately get destroyed when you
leave/close the view by a GET request, but it is not accessible the
usual way anymore. JSF stores the bean in the UIViewRoot#getViewMap()
with the managed bean name as key, which is in turn stored in the
session. You need to return null or void from action (listener)
methods to keep the bean alive. Use this scope for more complex forms
which use ajax, data tables and/or several rendered/disabled
attributes whose state needs to be retained in the subsequent requests
within the same browser window/tab (view).
in the function I just change to void and jsf won't call the init() again.

Using navigation rules inside a jsf bean

I've created a bean to search an sql table. This bean produces an arraylist that is displayed in a rich:dateTable. For each row in this table, there is a column that is a link to another page that specifies which record in the table is to be displayed, e.g.:
<h:link id="profile_last_name" value="#{record.string}" outcome="#{search.action()}">
<f:param name="user_id" value="#{record.getInteger('user_id')}"/>
</h:link>
The search bean is passed a navigation outcome, e.g. "staffEditUser" that creates a URL like:
http://localhost:8080/staff/edit/user.xhtml?user_id=98
I'd like to change the search bean so that if there is only one row in the search result, it immediately goes to the edit page. I know how to do the redirect if I knew the destination page name but I don't; all that I know inside the search bean is the navigation outcome. Is there some way to access the navigation rules from inside the bean?
Alternatively, and this seems very kludgy to me, could I simply add parameters to a redirect in the xhtml file that would be processed by the jsf navigation? If so, how?
Thanks very much for any help.
You can redirect the JSF page from within your managed bean method with
FacesContext.getCurrentInstance().getExternalContext().redirect("url");
As I understand you. You should check inside your ManagedBean database read method if the returned results have the size of none and then redirect to the edit page of this record.

jsf clearing the form

I need help. I'm new to JSF and im using JSF2 and richfaces in my project.
I want to clear the form for which I'm using <f:ajax render="#form"/> in refresh button. I have an ADD button on that screen which adds one record and I hit refresh then it's going to the default page. But when I once again go to enter a record then those values which I entered earlier remain in the form fields.
Can anyone please help me out with this issue?
Assuming that you mean the browser's refresh button when you say "I hit refresh", then that can happen if you've incorrectly placed the bean holding view scoped data in the session scope. You're then basically reusing the very same bean as the form is previously been submitted to. Putting the bean in the view scope instead of the session scope should fix this problem. The view scope ends when you navigate to a different page or fires a new request (as by hitting browser's refresh button).
See also:
How to choose the right bean scope?
Update if you're due to bad design restricted to using session scope, then you might want to hack this around by a
<f:event type="preRenderView" listener="#{sessionScopedBeanWhichShouldActuallyBeViewScoped.resetModel}" />
with
public void resetModel() {
if (!FacesContext.getCurrentInstance().isPostback()) {
model = null;
}
}
This will clear the model on every GET request. However, regardless of this hack, you'll still run into serious problems when the enduser opens the same view in a different browser tab/window within the same session.
The right solution is to put the bean in the view scope instead of the session scope, as said earlier.

Is there any way to have a bean in ViewScope and RequestScope at same time

I have a table of Items, and in each row there is a link that forwards to the edit item page. To load data in the edit page I need the managed bean in request scope (if I put it in view scope I loose data in the forward).
To use ajax in the edit page I need the managed bean in view Scope due to some values I must keep. If I were working with JSF 1.0 and RichFaces I would do it with request scope and a4j:keepalive.
How do I get this funcionality with PrimeFaces and JSF 2.0 or how can I redefine the interface to get this?
Ok, finally based on the post below this is what worked for me:
CommandButton in the Items table:
<o:commandButton id="editButton"
action="#{itemTableMB.editItem(item.id)}" styleClass="botonTabla">
<h:graphicImage styleClass="imagenBotonTabla" url="/resources/images/icons/pencil.png"/>
</o:commandButton>
Action in the managed bean:
public String editItem(Integer id){
return "/pages/items/edit.xhtml?faces-redirect=true&id="+id;
}
edit.xhtml:
<f:metadata>
<f:viewParam id="id" name="id" value="#{itemMB.item.id}" required="true">
</f:viewParam>
<f:event type="preRenderView" listener="#{itemMB.loadItem}" />
</f:metadata>
Listener in itemMB:
public void loadItem(){
this.item = this.itemManager.get(this.item.getId());
}
To load data in the edit page I need the managed bean in Request scope (If I put it in view scope I loose data in the forward).
Are you using a navigation rule (or implicit navigation) without a redirect?
One solution would be to put backing beans of both the "table of items"-page and the "edit item"-page in view scope, and then go from the first to the second one directly via a GET request (e.g. using <h:link>) or a POST/redirect with a request parameter representing the row on which the user clicked.
Use <f:viewParam> on the second page to conveniently convert the request parameter back to an entity representing the item being edited.
If you were indeed using navigation without redirect, then this has the additional benefit that you won't suffer from the notorious 'one-URL-behind-problem', which can be rather confusing to users of your application and be a nightmare for support.

How to update the JSF sessionscoped managed bean if i access it?

As title.
The problem is the attribute in the bean is fixed after init().
I want to update the count attribute when ever i access #{managedBean.xyz} method in JSF
I want to stick with the sessionscoped instead of view/request because it saves some time for the Object re-creation.
I don't want to do the attribute update manually in every xyz function. thanks
If I understand you correctly, you want to invoke a bean method on every view which involves the bean?
Add <f:event type="preRenderView"> to those views.
<f:event type="preRenderView" listener="#{managedBean.countUp}" />
with
public void countUp() {
count++;
}
It will be invoked only once on every request.

Resources