How can I add FacesMessage during page load? Using @PostConstruct does not seem to work
In a backing bean's @PostConstruct method, I make a call to an EJB which might return some messages that I want to display on the page via p:messages. However, even if I add the FacesMessages e.g. FacesContext.getCurrentInstance().addMessage(...), p:messages is not being updated with the FacesMessages.
If I instead invoke the call to the EJB on an action from the page (say a user clicks a button on the page which invokes a method that calls the EJB and then adds the FacesMessage(s)), then the messags show up using p:messages as expected.
How do I add Faces Messages during @PostConstruct and have them show up when the page is initially rendered?
Code:
Page1Controller.java:
@ManagedBean
public class Page1Controller
{
@PostConstruct
public void init()
{
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("Test Message from @PostConstruct"));
}
public String getValue()
{
return "Some Value";
}
public void triggerMessage(ActionEvent event)
{
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("Test Message from Trigger Button"));
}
}
page1.xhtml
<h:form>
<p:messages showDetail="true" showSummary="true" autoUpdate="true"/>
<h:outputText value="#{page1Controller.value}"/>
<br/>
<p:commandButton value="Trigger Message"
actionListener="#{page1Controller.triggerMessage}"/>
</h:form>
That can happen when the message component is rendered before the message is added.
In your specific example, the bean is referenced for the first time by the <h:outputText>
component and thus constructed for the first time at that moment. But the <h:outputText>
component appears in your specific example after the <p:messages>
component, so the <p:messages>
component is already rendered and thus it's too late to show the message.
You need to make sure somehow that the message is added before the message component is rendered. One way is using <f:viewAction>
. It runs during INVOKE_APPLICATION
phase which is before RENDER_RESPONSE
phase. Thus it runs before any component is rendered. A perfect opportunity thus.
<f:metadata>
<f:viewAction action="#{bean.onload}" />
</f:metadata>
public void onload() {
// Add message here instead of in @PostConstruct.
}
See also:
- What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
You can collect the error and then display it at the end of loading the page using a remoteCommand of primefaces with autorun = true mode. In my case I have a viewScope and in xhtml I show the list of values that are loaded in the @PostConstruct. If an Exception is generated I will save it to the sample at the end of the page load if it exists using the remoteCommand.
private ArrayList<Exception> postConstucError = new ArrayList<>();
@PostConstruct
public void validarAcceso() {
/**
* verificar permisos a la vista de coeficientes
*/
try {
this.init() //load data;
} catch (Exception e) {
System.out.print(e.getMessage());
this.postConstucError.add(e);
}
}
public void showPostConstructError() {
try {
for (int i = 0; i < this.postConstucError.size(); i++) {
JsfUtil.addErrorMessage("Error al cargar datos iniciales: " + postConstucError.get(i).getMessage());
}
} catch (Exception e) {
JsfUtil.addErrorMessage(e, "Error: showPostConstructError() " + e.getMessage());
}
}
xhtml code
<p:messages id="messages" showDetail="true" autoUpdate="true" closable="true"/>
<h:form>
<p:remoteCommand id="rcomerror" name="showError" process="@this" autoRun="true"
actionListener="#{mBPresentNinos.showPostConstructError()}" />
</h:form>