How to show a personalized error/warning/info message in a popup window? - jsf

Hi I want to show a popup message about errors or warnings in my app, for example if a user try to enter a registry that is already in the data base. I'm working with JSF and my app doesn't add a registry that is already in the data base but I need to show a message that informs the user about that.
Thanks.

This answer is specifically for icefaces (since I read in comments that the #Mel is working with icefaces.
To open a popup in icefaces:
<ace:dialog widgetWar="mydialog">
<h:outputText value="This is a dialog" />
</ace:dialog>
Then call this popup in your xhtml code like this:
E.g. I am using a command link that when clicked opens the popup.
<h:commandLink onlick="mydialog.show()" action="#{myBean.doSomething()}" />
To show messages in dialog:
<h:form id="myform">
<ace:dialog id="mydialog" widgetWar="mydialog">
<h:panelGrid columns="1" width="100%">
<ace:messages id="allMsgsAdd" initEffect="highlight" for="myform:mydialog" />
</h:panelGrid>
<h:outputText value="This is a dialog" />
</ace:dialog>
</h:form>
Then you can use this code to push messages to the ace:message you just created.
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(SEVERITY_INFO, "My Message", null));
Please note that SEVERITY_INFO is a FacesMessage defined constant. You will need to import it. Depending on whether you need to show warning or error to user, you can import these
import static javax.faces.application.FacesMessage.SEVERITY_ERROR;
import static javax.faces.application.FacesMessage.SEVERITY_INFO;
Also note the first parameter of addMessage() method. You will notice that I am passing null as the first paramter. See here, and you will find that the first paramter is the client id, which basically means that which client do you want to send this message to. If clientId is null, this FacesMessage is assumed to not be associated with any specific component instance. So all of the message dialogs in your page will receive this error/warning. If you wish to ONLY show the message on the dialog, you need to pass your dialog client id here like this:
FacesContext.getCurrentInstance().addMessage("myform:mydialog", new FacesMessage(SEVERITY_INFO, "My Message", null));

You can try to use some existing open source JSF component library .Many of them already provide the pop-up UI . For example ,Richfaces provides it by . You can refer to this official link to see how to use : http://docs.jboss.org/richfaces/latest_3_3_X/en/devguide/html/rich_modalPanel.html

Check my asnwer in another question, maybe it will be useful for you
How do I get a richfaces modal window to display without an onclick event?
This will show your exception messages (or another message added by you in middle of the code) in a <rich:modalPanel>.

Related

Close dialog prior to navigate away from the page

PrimeFaces: 7.0
JSF: 2.2.13
JBoss: 7.1
Java: 1.8
Chrome: 83.0.4103.116
I have a simple confirmation dialog to go to another page, there a reason for the action should be provided as a text.
It boils down to the following lines of code:
<p:dialog id="dlg" widgetVar="dlg" modal="true">
<h:form id="dlgForm">
<p:inputText id="reason" required="true" value="#{bean.reason}"/>
<p:message for="reason"/>
<p:commandButton id="proceed" value="Proceed" update="dlgForm" action="#{bean.action}"/>
<p:commandButton id="cancel" value="Cancel" resetValues="true" onclick="PF('dlg').hide()">
<p:ajax update="dlgForm" resetValues="true"/>
</p:commandButton>
</h:form>
</p:dialog>
And the bean:
#ManagedBean(name = "bean")
#SessionScoped
class Bean {
public String processGrundFuerExportDlg() {
PrimeFaces.current().executeScript("PF('dlg').hide()");
return "other_page";
}
}
My requirements:
Dialog opens with the empty 'reason'-inputText.
If 'cancel' is pressed: dialog should close
If 'proceed' is pressed:
If reason is not empty: close dialog and navigate to the 'other_page'
If return is empty: show the error message and don't close the dialog
My problem with this code: the line
PrimeFaces.current().executeScript("PF('dlg').hide()");
seems to be executed AFTER the current page being left resulting in 'dlg' not being found (JavaScript error).
The not properly closed dialog produces a nasty side effect: After returning to my first page later on, the dialog overlay stays active and inputText elements can't be activated with the mouse (TAB works). Overlay logic in the event loop blocks mouse clicks to from being passed to the components on the page.
My question:
How this standard scenario should be properly implemented with JSF and PrimeFaces?
If Upgrade to other versions is required, are there some workaround for removing stale overlays without upgrading?
Disclaimer: I studied many related questions on StackOverflow and tried all proposed solutions without success. For example this one: Keep p:dialog open when a validation error occurs after submit
You won't be having this problem if you would redirect to the new page instead of triggering an Ajax update.
You can simply add ?faces-redirect=true to your returned string, so:
return "other_page?faces-redirect=true";
Or, if you are using faces-config, add <redirect/> to the <navigation-case>.
Then you can remove the script from your bean where you try to close the dialog.
See also:
How to navigate in JSF? How to make URL reflect current page (and not previous one)
If 'proceed' is pressed:
If reason is not empty: close dialog and navigate to the 'other_page'
If return is empty: show the error message and don't close the dialog.
All this above is handled with required true on reason inputText. If reason is empty action in proceed commandButton won't start.
You don' need to close your dialog before you are navigating to other page.

Update JSF messages after initial rendering via p:menuitem

Does anyone know if it's possible to update a JSF message or messages element AFTER its initial rendering via PrimeFaces' p:menuitem?
For example, I have a PrimeFaces p:menuitem I am using to open a p:dialog, and that p:dialog has a p:messages element whose message I would like to update and show the moment that the p:dialog is opened - I can't know whether there is a message I want to show or what that message should be until after the p:menuitem's action method is complete.
Unfortunately, setting the update attribute of the p:menuitem to both the id of the p:dialog and the id of the p:messages element itself does not cause the p:messages element to show its message, even though I think it should since the action method of the p:menuitem looks like it is properly adding a message to the p:messages element.
The menuitem opening the dialog:
<p:menuitem value="Show Dialog with Message" action="#{myView.prepareDialogWithMessage()}" oncomplete="PF('dialogWidget').show()" update="dialogWithMessage message" />
The dialog with the message:
<p:dialog id="dialogWithMessage" widgetVar="dialogWidget" resizable="false" dynamic="true" closable="false" showEffect="fade" hideEffect="fade">
<p:messages id="message" for="message" showDetail="true" escape="false" autoUpdate="true"/>
<div class="button-panel">
<p:commandButton value="Yes" styleClass="ui-confirmdialog-yes" action="#{myView.submitAction()}" oncomplete="PF('dialogWidget').hide();"/>
<p:commandButton value="No" styleClass="ui-confirmdialog-no" onclick="PF('dialogWidget').hide();"/>
</div>
</p:dialog>
The Java code which adds the message:
public void prepareDialogWithMessage() {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_WARN, "Summary of message we want to show when the dialog opens", "Details of the message we want to show when the dialog opens");
FacesContext.getCurrentInstance().addMessage("message", message);
}
Short answer: It behaves exactly as expected and implemented.
Longer answer:
Having a closer look after your edited question, I noticed the dynamic="true" on the dialog. If you read the PrimeFaces docs it states (as you already found out):
dynamic: Enables lazy loading of the content with ajax.
So when you show the dialog via javascript, its content is updated... Since this content also includes the p:messages, that is also updated. In your case updated again with the messages that are generated in the ajax call of the update of the dialog... Most likely none... So the messages you added to it in the prepareDialogWithMessage() call of the menuItem are lost.
Since you already update the dialog in the call to the menuItem, the dynamic='true' is totally superfluous and it throws a spanner in the works.
<off-topic>A suggestion is to always start creating an [mcve]. Removing more and more until the behaviour of certain parts is as expected. Removing the dynamic='true' in one of the steps would have resulted in this and you'd have known a lot more. At the same time, also try debugging more. Investigating by looking at the requests and responses in the browser developer tool. You would have seen the messages getting added to the dialog and then the dialog(contents) being totally overridden. All these things are easy too (sorry, easy instead of 'not to difficult), can/will tell you a lot and helps getting to the cause of things quicker. Either directly, or by being able to ask way more specific question that is often easier to answer</off-topic>

Open dialog to register vehicle on the register of notes

Personally I have a registration page of notes, it got a selectOneMenu vehicle. But I want to offer the user the ability to click a button to open a dialog where he registers a vehicle if you do not already in the registry. And this is set back in the notes page to close the dialog. I know it sounds very simple. But would an example of how I can do this.I use JSF, Primefaces, JEE7 Thank you
Here's the most important, the buttons:
In main page, surrounded by form mainForm:
<p:commandButton icon="ui-icon-plus"
value="New"
actionListener="#{bean.prepareCreate}"
update=":formInDialog"
oncomplete="PF('dialogWidgetVar').show()"/>
In bean.prepareCreate you create the new entity for binding into.
In dialog, which has its own form formInDialog inside it:
<p:commandButton actionListener="#{bean.create}"
value="Save"
update=":mainForm:listOfEntities, formInDialog, :growl"
oncomplete="if(args && !args.validationFailed {PF('dialogWidgetVar').hide()}" />
formInDialog and growl needs to be updated in case of errors.

How do I update a menu bar in a calling template

As an exercise I want to have a menu bar which is disabled until the user logs in. When he logs in I want to call something which will trigger an update. The menu bar is in the master.xhtml template file
<h:form >
<p:menubar id="masterMenuBar">
<p:menuitem disabled="#{backing.disableMenu}" value="List users" />
</p:menubar>
</h:form>
As part of the login I have code to refresh the form
public void refreshForm() {
RequestContext context = RequestContext.getCurrentInstance();
context.update("form1");
context.update("masterMenuBar");
}
I tried my luck with calling a context update to my defined label of masterMenuBar but the RequestContext apparently doesn't include my calling template form (which sounds reasonable enough).
Is there some other context I can call which will include a context update to my menu bar? Perhaps I am on the wrong path, and there is a better way to achieve the same thing?
I did notice that even resizing the browser wasn't reason enough to call again to my backing.disableMenu bean. Apparently I need something fairly strong to cause it to reach my bean a second time.
You need to pass the absolute client ID, not the relative client ID. If you rightclick and view source in browser, then you'll see that the masterMenuBar element has the (autogenerated) ID of its form prefixed.
You need to give the form where the menu is sitting in a fixed ID
<h:form id="menuForm">
<p:menubar id="masterMenuBar">
...
and pass the absolute client ID instead.
context.update("menuForm:masterMenuBar");
Update: sorry, it shouldn't start with : in contrary to the update attribute of <p:commandButton>.

How to clear h:message or rich:message value in JSF?

I am developing a JSF application and I have many user forms where I use JSF validations.
I have an issue which annoys me, it will be easier to tell it with an example.
<h:panelGroup>
<h:selectOneRadio id="gender" value="#{registrationController.person.gender}"
required="true" requiredMessage="#{msg.commonErrorBlankField}">
<f:selectItems value="#{registrationController.genders}" />
</h:selectOneRadio>
<rich:spacer />
<rich:message for="gender" errorLabelClass="errorLabel">
<f:facet name="errorMarker">
<h:graphicImage value="#{msg.imageExclamation}" />
</f:facet>
</rich:message>
</h:panelGroup>
Above if a radio option is not selected a required message is displayed. And when the user makes a selection I see the validation error disseapeares. Fair enough !
My problem is when the user navigates to next page and then by using back button of the browser comes back to this page again I can see my gender field is selected accordingly but validation error is still displayed.
Does anyone know if there is a workaround to clear the h:message field once I click the command button so validation error won't be displayed when I go back to the same page?
Not sure if this works. I have not tested it:
//idComponent is the Component whose message you want to clear, e.g. gender
void clearMessageForComponent (final String idComponent) {
if (idComponent != null) {
Iterator<FacesMessage> it = FacesContext.getCurrentInstance().getMessages(idComponent);
while(it.hasNext()){
((FacesMessage)it.next()).setDetail("");
}
}
}
It is important to understand that the browser back button won't trigger a request to the server.
that is not entirely correct, modern browsers do trigger a request if data was posted in previous stages of the navigation.
Clearing the Messages from the FacesContext won't fix your problem, since this will affect only the server side state of your application. Pushing the browser back button forces the clients browser to reload the page from the local browser cache.
It is important to understand that the browser back button won't trigger a request to the server.

Resources