How can I use a shared error message Dialog in PrimeFaces - jsf-2

In PrimeFaces, when you want to show an error Message you can:
create in View a command Component that calls an action
in 'update' attribute, you set the id of the p:message or p:growl component that will display the message
in The backing Bean, in the action function you throw a message
As a result, the error message will be displayed in the redirect page, in the message component with the matching id
But what if :
You want to display the message in another page, that doesn't contain the command component that called the action.
The action can redirect to lots of different pages, depending on some Backing bean Logic.
The action is not called from a command Component, at least not directly
I've thought of putting a p:message component with a specific id, and include it in every xhtml page. But this would not necessarily cover the 3rd scenario.
For example, there could be a function that checks the connection to another Web Service. A Connection error could be thrown from lots of different Actions.
Or a session expiration
Or a denial of permission
How would you manage this kind of generic error messages ?

You could put the common <p:dialog> or <h:message> in a template file which is being used for all pages and give it a unique id. That way, it will be rendered for all the pages using that template.
This, is assuming that you're using templates that is.
UPDATE: If you wish to programmatically update the component, you can do so using RequestContext#update()
For e.g.
if (someErrorCondition) {
RequestContext.getCurrentInstance().update("errorDialogId");
}
where errorDialogId is the ID of the common error dialog.
If you intend to use this approach, you need to remove the update atribute from your command component.
See Also
Calling Primefaces dialog box from Managed Bean function

Why not use the RequestContext#showMessageInDialog(FacesMessage)?
As per their User Guide:
Displaying FacesMessages in a Dialog is a common case where a
facesmessage needs to be added to the context first, dialog content
containing a message component needs to be updated and finally dialog
gets shown with client side api. DF (Dialog Framework) has a simple utility to bypass
this process by providing a shortcut;
Using this you don't need to have additional codes to put in every page you have. Just add it in your beans.

Related

Handling application exceptions and bean validations in JSF2 managed bean

I am building a JSF2 application with multi-lingual content.
1) Bean validation will be used for validating the form fields. I use ValidationMessages properties files to define locale specific error messages and use the <h:message> tag for displaying the correct error message on screen.
2) For application specific exceptions, I currently have a generic ApplicationException which is handled in managed bean methods. Inside the exception catch block, I set a "msg" field in the bean with a custom error message (For e.g: "The inventory cannot be updated as no matching product code found").
In the xhtml pages, I check if the "msg" string is not empty and display it on top of the page.
Is there a better way to handle display of success and error messages in JSF?
Can I simply throw the ApplicationException in managed beans and have a generic handler to handle the exceptions and display messages in the relevant view?
I read https://weblogs.java.net/blog/edburns/archive/2009/09/03/dealing-gracefully-viewexpiredexception-jsf2, but I am not able to map it to my requirement
You're doing it almost properly. The way for the component validations is the one to go. However, for your managed bean logic, it's not necessary to implement a custom String property in your bean. Just add the message you want in your action method and it will be displayed by the h:messages tag:
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
"The inventory cannot be updated as no matching product code found","");
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, message);
Using an ExceptionHandler for just displaying a message seems overcomplicated. It also won't work for asynchronous (Ajax) requests, unless you use a third party solution like Omnifaces.
See also:
JSF 2 Global exception handling, navigation to error page not happening

Open a new tab don't create new ViewAccessScoped bean

I have a sample use case: I have an edit page that use GET parameter "id".
eg. edit?id=1
This edit page is backed by a ViewAccessScoped (CODI) Bean.
In this edit page, I have a datatable with links that link to the same "edit" page, but with another id. (eg. edit?id=2)
<h:link value="#{mecaPart.id}" outcome="edit" target="_blank">
<f:param name="id" value="#{mecaPart.id}" />
</h:link>
The problem, is that the window open correctly, but it is the same bean that is used! And so I am editing the same part...
I have placed a log in #PostConstruct, and it is the same bean reference that is called multiple times. (even with the new ID!)
My question, how can I tell JSF to create a new ViewAccessScoped backing bean when I click the link, and not re-use the actually used one?
Finally, I discovered that #ViewScoped CODI bean did not preserved the backing bean from page refresh. So, I have to use ViewAccessScoped.
According to Gerhard Petracek: http://os890.blogspot.fr/2011/08/scopes-view-scope-vs-view-access-scope.html
the view-scope of jsf2+ is bound to a concrete jsf page. that means: as soon as you navigate to a different page, the state gets lost. that's better than nothing, but not useful for a lot of use-cases. the main use-case which needs it are ajax-requests on a page and the data used by them aren't needed on other pages, but it's pretty easy to break it e.g. with a browser-refresh on a page which stores the data in a view-scoped bean and has no form with input components. (in a previous blog post i described how to use the infrastructure provided by codi to create a session based view-scope to overcome such disadvantages cause by storing view scoped beans as part of the tree-state.)
like with the view-scope view-access-scoped beans are available on a page, but they also exist for the next page. that means: they are forwarded to the next page and get destroyed autom. if they don't get used during the first request of the next page. that's e.g. useful for wizards. if you have a wizard page which doesn't use the bean or you have to support the possibility to interrupt a wizard, you can use the grouped-conversation scope (and even the window-scope) provided by codi. however, due to the powerful api of codi you can also destroy the scope manually at any time (if needed).
So, to solve the problem of opening a new tab with another "ID", I had to set "CODI Client Side WindowHandler", according to the CODI Wiki.
https://cwiki.apache.org/confluence/display/EXTCDI/JSF+WindowHandler
So I added:
<alternatives>
<class>org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.ClientSideWindowHandler</class>
</alternatives>
To the file beans.xml, and I used #ViewAccessScoped. Everything is working smoothly now.
You can use #ViewScoped which also works in CODI

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.

Selenium and JSF 2.0

When I a generate SelectOneMenu with JSF2.0 the the id I specified in the xhtml is attached to a generated ID from JSF.
e.g. out of my_fancy_id it generates j_idt9:my_fancy_id
Now I want to test my page with Selenium 2 Web Driver. I try to re-find my select menu:
driver.findElement(By.id("my_fancy_id"));
Of course it does't find anything because the id is changed. What is the best way to find the select menu on the page?
Usually the id of the form is prepended to all element ids inside the form. If you don't set a form id, JSF does it for you (the 'j_idt9'). Solution: Assign an id to your form and try to use the full id in your findElementmethod, e.g.:
<h:form id="myForm">
...
</h:form>
Call it this way:
driver.findElement(By.id("myForm:my_fancy_id"));
or you can add <h:form prependId="false"> so that the id of the form does not get prepended
You set the component identifier on controls; the renderers emit the client identifier to the markup.
This allows JSF to emit valid HTML ids (they must be unique) even in the face of templates and complex controls. A control will be namespaced by any parent that is a NamingContainer (such as a form).
In some containers, the client identifier will be namespaced by the view, but this generally only happens in portlet environments.
Some component libraries (like Tomahawk) have a forceId attribute, but care must be exercised in using them. I wrote a more extensive post on client identifiers here.

Providing data to Menu in my ASP.NET MVC Master Page

We are beginning the process of moving from Web Forms to MVC for all of our new applications. I am working on porting our Master Page over and am trying to satisfy the requirements that we need a single master page to be used by all applications. The primary navigation for the application needs to be in a menu within the master page. Accomplishing this was easy, the hard part is that each application may need to determine what to display in the menu using a unique set of rules. Some apps can simply say, here's the menu structure to use via something like a SiteMap. Others need to determine what is displayed in the menu based on what roles the user has, this can also be handled easily with a SiteMap. The situation that I'm struggling with is that some apps need to generate the menus based on the roles the user has, but also on the data on which they are working. i.e. The same user may have different option in the menu for a page if they are working on object 'foo' than they do if working on object 'bar'.
What I've done at this point, is I've created an HtmlHelper that is called by the master page view and takes a list of objects of a custom type and returns an unordered list that is styled by a jQuery plugin to display the menu. The list of objects the helper method takes are passed to the view using the ViewData dictionary. Currently, the value of this ViewData node is set within the constructor of each controller. This allows each page, and potentially each method, to set a different menu without having to set the value in each action method, unless its needed. I have also created a class that parses a SiteMap and returns the list of items needed to build the menu. This class is what I'm using to set the ViewData value in the controller. The idea being that if an application needed more control of how the menu data was generated, they could create their own class to generate the data as long as it returns a list of the correct type of objects.
This solution seems to work fine so far, it just doesn't 'feel' right for some reason. I'm hoping that I can either get some ideas of better way to do this or some reassurance that this is a valid approach to solving this problem.
If it is something that will be on every page, do something like this:
Create a base controller:
public class MyBaseController : Controller
Have this controller get the data it needs and send that data in the ViewData["menu"] to the View. Then have all your controllers inherit from this one:
public class HomeController : MyBaseController
In the Master Page, loop through your ViewData and create your menu.
(I did something like this for my sub-menu which displayed a list of categories.)
In the book I am reading (Pro ASP.NET MVC Framework by Apress) they use Html.RenderAction for the menu in the masterpage. I am a Asp.net MVC novice so maybe somebody else can give more info about this.
You can download the sourcecode at apress.com though so maybe that could help.

Resources