Change commandLink Id by my code in datatable - jsf-2

I need a way to manage the creation of the commandlink ID in DataTable, the problem is that when i use it for deleting a record and interrupt the rendering of the page (reloading it by 'ctrl+f5' ) it assigns the same id to another link button, which results in deleting the row containing it.

The problem in question is sound, but the requested solution is not the right one and not easily to achieve in JSF — basically, you'd need to homebrew a custom command link renderer which is designed specifically for usage in data tables and is able to recognize the specific entity.
The right solution is send a redirect to the same view after POST.
public String delete() {
// ...
return FacesContext.getCurrentInstance().getViewRoot().getViewId() + "?faces-redirect=true"; // Feel free to hardcode the view ID, though.
}
(if you intend to display some faces message along it, use the flash scope)
A browser refresh would then result in only the redirect being refreshed rather than the POST action.
An alternative is to submit by ajax instead.
<h:commandLink ...>
<f:ajax execute="#form" render="#form" />
</h:commandLink>
A browser refresh would then only re-execute the last synchronous request, which would be the initial GET request which opened the page in question.

Related

OmniFaces' enableRestorableView restores empty view root

I have a page anchors.xhtml which contains a form and an
<h:commandButton action="#{anchorsBean.onRefresh}" value="Refresh" />
which submits to the same page using redirect:
public String onRefresh() {
refresh();
return "anchors?faces-redirect=true";
}
I want to avoid ViewExpiredException on session timeout or caused by other reason. For that purpose I get use of OmniFaces' restorable view handler:
<f:metadata>
<o:enableRestorableView />
</f:metadata>
But surprisingly at this point, in case of expired view, my redirection behavior gets lost: POST request/response simply takes place. Some digging into details reveals me that navigation/redirection is normally triggered by UICommand at Invoke Application phase, however the view root restored by <o:enableRestorableView /> seems to have no children at all. So there's simply no command component to call the default action listener which must handle redirection.
I am using Mojarra 2.1.19 and OmniFaces 1.4.1. I can see in the sources that RestorableViewHandler creates the view but does not build it: can it be the reason for the empty UIViewRoot? Evidently, there's something I am flagrantly missing and misunderstanding...
Most interesting, when I use no <o:enableRestorableView /> but simply remove ViewExpiredException event in my custom exception handler, everything works fine: FacesContext happens to somehow already contain a fully built UIViewRoot (which <o:enableRestorableView />, when included, will later replace with an empty one). So this way I'm getting the originally desired behavior, at least things look like that. But this way is definitely wrong I suppose.
Many thanks in advance for any clarification on this.

Difference in navigation by action="xyz" and action="#{bean.returnXyz}"

How is navigation from a Facelet page
<p:commandLink action="xyz.xhtml">
or a backing bean
<p:commandLink action="#{bean.redirect}">
public class Bean{
public String redirect(){
.....
return "xyz.xhtml";
}
}
different from each other?
How is navigation from a xhtml page or a backing bean different from each other.
There's no difference. The both examples invoke a POST request and instructs JSF to render the view associated with the given outcome. The backing bean method has the only advantage that it allows you to perform some business logic beforehand or even control the outcome value programmatically.
However, if you don't have any business logic at all and solely want to have an idempotent link to another page, then using a command link is actually a bad practice. Using POST for page-to-page navigation is not user nor SEO friendly. The target page is not bookmarkable (the URL remains the one of the page where the POST form was been submitted to) nor searchbot-crawlable (it is using JavaScript to submit a hidden form).
You should instead use a normal link.
<h:link outcome="xyz.xhtml">
This generates a SEO-friendly <a> element with the full URL in its href and ends up in an user-friendly bookmarkable URL.
See also:
When should I use h:outputLink instead of h:commandLink?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Check out the documentation of p:commandLink here, which says the following for action attribute:
A method expression or a string outcome to process when command is
executed.
Now, as action="xyz.xhtml" returns String xyz.xhtml you're redirected accordingly and for action="#{bean.redirect}" which again returns xyz.xhtml you are again redirected according to the returned String.

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.

Can one action result leads to two different jsp pages in struts2?

My question is:
I have one pop up window to validate some content, and i use action class to do the validation(javascript not allowed). If the content is valid, i need to close this pop up window, and update the content in the main page.
My idea is in my struts.xml, i mapped
<result name="add" type ="redirectAction"> mainpage.jsp</result>
is it possible to add
<result name="add" > popupCurrentPage.jsp</result>
to let the same action result leads to two diffent pages at the same time?
Browsers may receive a single response for any request.
Doing multiple things on the client side based on a response requires JavaScript somewhere.
Use it's possible to add the tag in main page.
<s:include value="popupCurrentPage.jsp"/>
but when you are redirecting you will miss the valuestack data, so use messageStore interceptor.

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.

Resources