JSF FacesContext#addMessage is not displayed - jsf

In my previous question I had the problem of displaying validation messages from a Login form. That issue is now solved, but this time I am not able to display a custom message with FacesContex#addMessage.
Using JSF + PrimeFaces.
<p:dialog header="Login" widgetVar="loginDlg">
<h:form id="loginForm">
<h:panelGrid columns="3" cellpadding="5">
<h:outputLabel for="username" value="Username:" />
<p:inputText value="#{loginBean.username}" id="username" required="true" label="username" />
<p:message for="username" />
<h:outputLabel for="password" value="Password:" />
<h:inputSecret value="#{loginBean.password}" id="password" required="true" label="password" />
<p:message for="password" />
<f:facet name="footer">
<p:commandButton value="Login" id="loginDlgButton" update=":loginForm,:welcomeMsg" actionListener="#{loginBean.login}"
oncomplete="handleLoginRequest(xhr, status, args)"/>
<p:message for="loginDlgButton" />
</f:facet>
</h:panelGrid>
</h:form>
</p:dialog>
In LoginBean (a SessionScoped ManagedBean):
public void login() {
FacesContext context = FacesContext.getCurrentInstance();
RequestContext rContext = RequestContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
try {
request.login(this.username, this.password);
rContext.addCallbackParam("loggedIn", true);
} catch (ServletException e) {
rContext.addCallbackParam("loggedIn", false);
context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN, "Login Error", "Invalid credentials"));
}
}
This code, when validation succeeds and login fails, should display the "Invalid credential" message, but doesn't. Moreover, somewhere in the body of my web page, I have also added this line:
<p:messages autoUpdate="true" />
but my message isn't displayed even there.
Javadocs say that
If clientId is null, this FacesMessage is assumed to not be associated with any specific component instance
But I can't understand what this means.

place <p:messages autoUpdate="true" /> inside your form or inside some wrapper that is being updated by update of your commandButton , or place loginDlgButton instead of null in context.addMessage(...

I don't see a p:messages tag in your code. It is not the same as the p:message tag. p:message is attached to another component and is displayed as part of validation. The p:messages (or p:growl) component is what you are updating in your bean. Try adding a messages or growl component like this:
<h:form id="loginForm">
<p:growl id="messageGrowl" showDetail="true" sticky="false" />
<h:panelGrid columns="3" cellpadding="5">

Related

Primefaces messages for validation and growl for the rest

I have a JSF page with primefaces and I would like to use p:messages for the messages of the input validations and a Growl element for the rest of the things like notifications, errors ...
At the moment I have a Growl with attribute for and I'm sending notifications with this for attribute.
The problem is that I don't know which for attribute I have to put in the p:messages component. If I left it as null the notification messages are showing in Growl and on p:messages.
Here you can see an example of my JSF.
<p:growl id="growlNotifyNewReg" for="growlNotificationsNewRegister"
showSummary="true"
showDetail="true"
autoUpdate="true"/>
<h:outputText value="Validado"/>
<p:selectBooleanCheckbox id="checkValidado" value="#{}" required="true"/>
<h:outputText value="Temperatura (ÂșC)"/>
<p:inputText id="Temperatura" value="#{}" required="true">
<f:validateDoubleRange minimum="-50" maximum="60" />
<f:convertNumber maxFractionDigits="1" />
</p:inputText>
<!-- Other inputs... -->
<p:messages showSummary="true" showDetail="true" redisplay="false"/>
When I want to send a notification I do like this.
FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, "summary", "details");
FacesContext.getCurrentInstance().addMessage("growlNotificationsNewRegister", facesMsg);
This code sends messages to Growl component but also to messages component because it doesn't have for attribute. I want to know which attribute I have to put in messages component to show only the validations messages of the form.
As you can see I put redisplay attribute to false. Can I put multiple ids in the for attribute of the p:messages?
Here is an example works as you want, you can change it according to your code :
in .xhtml
<h:form prependId="false">
<p:growl id="growl" for="msg" showDetail="true" sticky="true" />
<p:panel header="Growl">
<h:panelGrid columns="2" cellpadding="5">
<p:outputLabel for="msg" value="Message:" />
<p:inputText id="msg" value="#{growlView.message}" required="true" />
<p:outputLabel for="msg2" value="Message2:" />
<p:inputText id="msg2" value="#{growlView.message2}" required="true" />
</h:panelGrid>
<p:commandButton value="Save" actionListener="#{growlView.saveMessage}" update="growl" />
</p:panel>
<p:messages id="messages" for="msg2" showDetail="true" autoUpdate="true" closable="true" />
</h:form>
in the for attribute for both <p:growl> and <p:messages> you can add whatever Ids you want just like for="id1 id2 .."
in bean
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
#ManagedBean
public class GrowlView {
private String message;
private String message2;
// setters / getters
public void saveMessage() {
FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, "summary", "details");
FacesContext.getCurrentInstance().addMessage("msg", facesMsg);
}
}

Getting a NullPointerException while Partial rendering via FacesContext

I have a strange behavior where I am getting NPE while doing page refresh using faces context.
I have a managed bean which is in Request Scope. So want to refresh the page after click on commandbutton. I have tried with 'update' but it is behaving strange in my page.
Error: PartialViewContextImpl$PhaseAwareVisitCallback.visit : java.lang.NullPointerException
This is my JSF page:
<h:form id="form">
<p:messages autoUpdate="true"/>
<h:panelGrid columns="4" cellpadding="5" id="panelGrid" rendered="true">
<p:outputLabel for="s00" value="#{tk.expense_keyword}"/>
<p:inputText id="s00" value="#{expense.form.keyword}"/>
<p:outputLabel for="s02" value="#{tk.expense_creatorId}"/>
<p:inputText id="s02" value="#{expense.form.creatorId}" disabled="#{!expense.form.canEditCreatorId}"/>
<h:outputText id="s10" value="Amount Between #{expense.form.amountFrom} and #{expense.form.amountTo}" />
<h:panelGrid>
<p:slider for="s11,s12" display="s10" minValue="0" maxValue="1000" style="width: 200px" range="true" displayTemplate="Amount Between {min} and {max}" />
<h:inputHidden id="s11" value="#{expense.form.amountFrom}" />
<h:inputHidden id="s12" value="#{expense.form.amountTo}" />
</h:panelGrid>
</h:panelGrid>
<p:commandButton value="#{tk.expense_search}" id="a01" action="#{expense.search}" ajax="false" immediate="true"/>
<p:dataTable var="line" varStatus="loop" value="#{expense.form.expenseEntryList}" emptyMessage="#{tk.expense_table_empty}" id="dataTable">
<p:column headerText="#{tk.expense_table_creatorId}">
<h:inputHidden value="#{line.oid}"/>
<h:inputText value="#{line.creatorId}"/>
</p:column>
<f:facet name="footer">
<p:commandButton value="#{tk.expense_saveAsDraft}" id="a06" action="#{expense.saveAsDraft}"/>
<p:commandButton value="#{tk.expense_submit}" id="a07" action="#{expense.submitAll}"/>
<p:commandButton value="#{tk.expense_validate}" id="a08" action="#{expense.validate}"/>
</f:facet>
</p:dataTable>
</h:form>
Here when I click on Save As Draft I want to refresh the page. So I am using FacesContext's method to refresh the page.
Here is my method saveAsDraft:
public Outcome saveAsDraft() throws Exception{
try {
saveAsDraftBody(false,false);
getFacesContext().getPartialViewContext().getRenderIds().add("form:panelGrid");**//**getting error****
getFacesContext().getPartialViewContext().getRenderIds().add("form:dataTable");**//**works fine****
Log.info(this,"getFacesContext().getPartialViewContext().getRenderIds(): "+getFacesContext().getPartialViewContext().getRenderIds());
return Outcome.SUCCESS;
}
catch (Throwable e){
throw manageError(e);
}
}
I don't know why it works for data table refresh but not for panelGrid :(
First of all you have the bean in request scope and you are making full page submit and here the partial render does not make any sense. The error you are getting because you have component which is basically, another input into a form which will be sent to the managed bean of the current view when the form is submitted.

Primefaces messages in a dialog is not displayed

I'm using Primefaces, and have a login dialog:
<p:dialog widgetVar="dlgLogin" header="Login" modal="true">
<p:outputPanel>
<h:form>
<p:messages for="msgLogin" autoUpdate="true" closable="true" showSummary="true" showDetail="false" severity="error"/>
<p:panel>
<h:panelGrid columns="2">
<p:outputLabel value="User Name"/>
<p:inputText id="userName" value="#{loginBean.userName}"
required="true" requiredMessage="User Name is required"/>
<p:outputLabel value="Password"/>
<p:password id="password" value="#{loginBean.password}"
required="true" requiredMessage="Password is required"/>
</h:panelGrid>
</p:panel>
<p:commandButton icon="ui-icon-arrowrefresh-1-n" value="Cancel" onclick="PF('dlgLogin').hide()"/>
<p:commandButton type="submit" value="Login"
ajax="false" validateClient="true"
oncomplete="handleClose(xhr, status, args);"
action="#{loginBean.login}"/>
</h:form>
</p:outputPanel>
</p:dialog>
Submitting the login is on purpose non ajax, so the entire page will be refreshed.
The server code is:
FacesContext.getCurrentInstance().addMessage("msgLogin", new FacesMessage(FacesMessage.SEVERITY_ERROR, "Wrong User Name or Password.", "Wrong User Name or Password."));
In case that the login fails in the server, I would like to display a message, and leave the dialog open. but it doesn't work.
How can that be done?
Thanks.
Don't close the dialog in JSF but in Java:
if (successfulLogin) {
RequestContext.execute("PF('dlgLogin').hide()");
} else {
FacesContext.getCurrentInstance().addMessage("msgLogin", new FacesMessage(FacesMessage.SEVERITY_ERROR, "Wrong User Name or Password.", "Wrong User Name or Password."));
}

p:commandbutton doesn't call method

I got a problem where one of my commandbuttons doesn't call the method I gave it and I have no idea why:
<p:layoutUnit position="center">
<h:form>
<p:dialog position="center" widgetVar="benutzerErstellen" visible="true" closable="false" resizable="false" draggable="false">
<h:panelGrid columns="2" cellpadding="5" styleClass="noBorders">
<h:outputLabel for="nachname" value="Nachname:" />
<p:inputText id="nachname" value="#{benutzerverwaltung.nachname}" required="true"/>
<h:outputLabel for="vorname" value="Vorname:" />
<p:inputText id="vorname" value="#{benutzerverwaltung.vorname}" required="true"/>
<h:outputLabel for="benutzername" value="Benutzername:" />
<p:inputText id="benutzername" value="#{benutzerverwaltung.benutzername}" required="true" validator="#{benutzerverwaltung.benutzerUeberschneidungValidate}"/>
<h:outputLabel for="teams" value="Teams:" />
<p:selectCheckboxMenu id="teams" label="Teams" scrollHeight="200" panelStyle="width:300px">
<f:selectItems/>
</p:selectCheckboxMenu>
<h:outputLabel for="passwort" value="Passwort:" />
<p:password id="passwort" feedback="true" value="#{benutzerverwaltung.passwort}" required="true" match="passwortBestaetigung" promptLabel="Bitte geben Sie ein Passwort ein." weakLabel="Schwach" goodLabel="Gut" strongLabel="Stark"/>
<h:outputLabel for="passwortBestaetigung" value="Passwort bestÀtigen:" />
<p:password id="passwortBestaetigung" value="#{benutzerverwaltung.passwort}" required="true"/>
<f:facet name="footer">
<p:commandButton id="erstellen" value="Benutzer erstellen" action="#{benutzerverwaltung.erstelleBenutzer()}"/>
</f:facet>
</h:panelGrid>
</p:dialog>
<p:growl/>
</h:form>
</p:layoutUnit>
This is the corresponding code:
erstelleBenutzer:
public void erstelleBenutzer(){
Benutzer benutzer = new Benutzer();
System.out.println(vorname);
benutzer.setVorname(vorname);
benutzer.setNachname(nachname);
benutzer.setBenutzername(benutzername);
benutzer.setPasswort(passwort);
this.benutzer.add(benutzer);
FacesMessage message = new FacesMessage("Benutzer wurde erstellt.");
message.setSeverity(FacesMessage.SEVERITY_INFO);
throw new ValidatorException(message);
}
benutzerUeberschneidungValidate:
public void benutzerUeberschneidungValidate(FacesContext ctx, UIComponent component, Object value) throws ValidatorException {
if (benutzerExistiert((String) value) || adminExistiert((String) value)) {
FacesMessage message = new FacesMessage("Benutzer existiert bereits.");
message.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(message);
}
}
I tried removing the validator, I tried removing the Exception from benutzerErstellen(), I tried giving the dialog it's own h:form and much more, but nothing worked. Anyone got an idea?
Earlier versions of PrimeFaces 3 have a bug wherein a commandButton or commandLink doesn't fire the action listener if it is located in the header or the footer.
See the post I have listed at the bottom.
p:commandButton action and f:setpropertyactionlistener not invoked in p:columngroup
I solved this like that
<p:dataTable>
...
<p:column>
...
<p:commandButton id="selectButton" update=":form:dataTable" icon="ui-icon-circle- close" title="Delete" action="#{myBean.doSomething}">
<p:ajax event="click" listener="#{mainPageBean.doRemoveEmployee(employee)}"/>
</p:commandButton>
...
</p:column>
...
</p:dataTable>

<p:focus> after page submit while staying on the same page does not work

I would like to use the Primefaces p:focus tag on a page that contains a form with input fields. Until the first commit the focus is set correctly. If I submit the form via a p:commandButton and return to the same page to show the error result (using FacesMessage messages), the focus is not defined (in Firefox the cursor blinks in the middle of nowhere).
How can I achieve a defined state of the focus? Can I choose which element has the focus after a submit?
Here are some code details:
The JSF page:
<p:panel header="Login">
<h:form>
<p:focus for="usernameInput" />
<p:panelGrid columns="2">
<p:outputLabel for="usernameInput">User name</p:outputLabel>
<p:inputText id="usernameInput" value="#{loginBean.username}" />
<p:outputLabel for="passwordInput">Password</p:outputLabel>
<p:password id="passwordInput" value="#{loginBean.password}" />
</p:panelGrid>
<p:commandButton value="Login" action="#{loginBean.login}" />
</h:form>
</p:panel>
<div>
<p:messages id="messages" globalOnly="false" autoUpdate="true" showDetail="true" showSummary="true" closable="false" />
</div>
The relevant parts of the Java class:
public String login() {
FacesContext fc = FacesContext.getCurrentInstance();
HttpServletRequest req =
(HttpServletRequest) fc.getExternalContext().getRequest();
try {
req.login(username, password);
return "/home?faces-redirect=true";
} catch (ServletException e) {
fc.addMessage(
null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error",
"error message")));
}
return null;
}

Resources