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>
For me using preRenderView event to display message on form init was a messages-hell. So I created very simple "component" to keep static messages. For this example only one error message is supported.
staticMessage.xhtml:
<ui:fragment xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
rendered="#{rendered}">
<div id="staticMessage" class="ui-messages ui-widget" aria-live="polite">
<div class="ui-messages-error ui-corner-all"><span class="ui-messages-error-icon"/>
<ul>
<li>
<span class="ui-messages-error-summary">#{value}</span>
</li>
</ul>
</div>
</div>
</ui:fragment>
Including messages:
<ui:include src="/template/components/staticMessage.xhtml">
<ui:param name="rendered"value="#{beanMB.staticMessagesRendered}"/>
<ui:param name="value" value="Place your message here."/>
</ui:include>
Related
I have tried to taste the new features of JSF 2.3, one attractive is the websocket.
I have read some sample codes from mojarra tests and JSF 2.3 specific #Push javadoc.
And encountered some issues when used f:websocket and f:ajax.
The facelets template is:
<h:panelGroup id="messagePanel" layout="block">
<ul>
<ui:repeat value="#{ajaxBean.messages}" var="m">
<li>#{m}</li>
</ui:repeat>
</ul>
</h:panelGroup>
<h:form id="form">
<h:commandButton
id="sendMessage"
action="#{ajaxBean.sendMessage()}"
value="Send Ajax Message">
<f:ajax/>
</h:commandButton>
</h:form>
<h:form>
<f:websocket channel="ajaxChannel" scope="view">
<f:ajax event="ajaxEvent" render=":messagePanel" />
</f:websocket>
</h:form>
<h:form>
<f:websocket channel="ajaxListenerChannel" scope="view">
<f:ajax event="ajaxListenerEvent" listener="#{ajaxBean.ajaxPushed}" render=":messagePanel" />
</f:websocket>
</h:form>
<f:websocket channel="commandScriptChannel" scope="view" onmessage="onCommandScript"/>
<h:form>
<h:commandScript name="onCommandScript" action="#{ajaxBean.commandScriptExecuted()}" render=":messagePanel"/>
</h:form>
And backend bean is:
#ViewScoped
#Named("ajaxBean")
public class AjaxBean implements Serializable {
private static final Logger LOG = Logger.getLogger(AjaxBean.class.getName());
#Inject
#Push
PushContext ajaxChannel;
#Inject
#Push
PushContext ajaxListenerChannel;
#Inject
#Push
PushContext commandScriptChannel;
private List<String> messages = new ArrayList<>();
public void ajaxPushed(AjaxBehaviorEvent e) throws AbortProcessingException{
LOG.log(Level.INFO, "ajax pushed: " + e.toString());
messages.add("ajaxListenerEvent is sent at: " + LocalDateTime.now());
ajaxListenerChannel.send("ajaxListenerEvent");
}
public void commandScriptExecuted() {
LOG.log(Level.INFO, "commandScriptExecuted pushed.");
messages.add("commandScriptExecuted message is sent at: " + LocalDateTime.now());
commandScriptChannel.send("onCommandScript");
}
public void sendMessage() {
// LOG.log(Level.INFO, "ajax pushed by button: " + e.toString());
messages.add("ajaxEvent is sent at: " + LocalDateTime.now());
ajaxChannel.send("ajaxEvent");
}
public List<String> getMessages() {
return messages;
}
public void setMessages(List<String> messages) {
this.messages = messages;
}
}
The result is the first button can trigger the ajax output as needed. But f:ajax with a listener does not work, and h:commandScript also does not work here.
How to correct these?
Your concrete problem is caused because you're nowhere in your code explicitly sending a push message to those websockets. If your attempt were possible in some way, the websocket would keep sending a push message to itself in an infinite loop. This doesn't make sense.
In order to explicitly send a push message, you have to let your code explicitly call push.send(message), exactly as you already did with that <h:commandButton>.
<h:form>
<h:commandButton value="Send push message" action="#{bean.sendPushMessage}">
<f:ajax />
</h:commandButton>
</h:form>
<h:form>
<f:websocket channel="pushWithAjaxUpdate" scope="view">
<f:ajax event="updateMessages" listener="#{bean.updateMessages}" render=":messages" />
</f:websocket>
</h:form>
<h:panelGroup id="messages" layout="block">
<ul>
<ui:repeat value="#{bean.messages}" var="message">
<li>#{message}</li>
</ui:repeat>
</ul>
</h:panelGroup>
#Inject #Push
private PushContext pushWithAjaxUpdate;
public void sendPushMessage() {
messages.add("Push message is sent at: " + LocalDateTime.now());
pushWithAjaxUpdate.send("updateMessages");
}
public void updateMessages() {
messages.add("Ajax event is received at: " + LocalDateTime.now());
}
I understand that you're just experimenting, but it should be said that above approach wouldn't make sense in real world code either. The <f:websocket> is superfluous in this specific use case and it would suffice to just use <h:commandButton><f:ajax listener="...">. It's in real world code expected that the push is not synchronously invoked by some command button in the very same page, but that it is asynchronously invoked by some business event. Otherwise you could as good just return the result in the ajax response itself. This saves an additional round-trip to the server.
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>
For me using preRenderView event to display message on form init was a messages-hell. So I created very simple "component" to keep static messages. For this example only one error message is supported.
staticMessage.xhtml:
<ui:fragment xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
rendered="#{rendered}">
<div id="staticMessage" class="ui-messages ui-widget" aria-live="polite">
<div class="ui-messages-error ui-corner-all"><span class="ui-messages-error-icon"/>
<ul>
<li>
<span class="ui-messages-error-summary">#{value}</span>
</li>
</ul>
</div>
</div>
</ui:fragment>
Including messages:
<ui:include src="/template/components/staticMessage.xhtml">
<ui:param name="rendered"value="#{beanMB.staticMessagesRendered}"/>
<ui:param name="value" value="Place your message here."/>
</ui:include>
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>
For me using preRenderView event to display message on form init was a messages-hell. So I created very simple "component" to keep static messages. For this example only one error message is supported.
staticMessage.xhtml:
<ui:fragment xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
rendered="#{rendered}">
<div id="staticMessage" class="ui-messages ui-widget" aria-live="polite">
<div class="ui-messages-error ui-corner-all"><span class="ui-messages-error-icon"/>
<ul>
<li>
<span class="ui-messages-error-summary">#{value}</span>
</li>
</ul>
</div>
</div>
</ui:fragment>
Including messages:
<ui:include src="/template/components/staticMessage.xhtml">
<ui:param name="rendered"value="#{beanMB.staticMessagesRendered}"/>
<ui:param name="value" value="Place your message here."/>
</ui:include>
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>
For me using preRenderView event to display message on form init was a messages-hell. So I created very simple "component" to keep static messages. For this example only one error message is supported.
staticMessage.xhtml:
<ui:fragment xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
rendered="#{rendered}">
<div id="staticMessage" class="ui-messages ui-widget" aria-live="polite">
<div class="ui-messages-error ui-corner-all"><span class="ui-messages-error-icon"/>
<ul>
<li>
<span class="ui-messages-error-summary">#{value}</span>
</li>
</ul>
</div>
</div>
</ui:fragment>
Including messages:
<ui:include src="/template/components/staticMessage.xhtml">
<ui:param name="rendered"value="#{beanMB.staticMessagesRendered}"/>
<ui:param name="value" value="Place your message here."/>
</ui:include>
I have an h:inputText and an h:message connected to it:
<h:inputText id="myText" value="#{myController.myText}" />
<a4j:outputPanel>
<h:message for="myText" .../>
</a4j:outputPanel>
I want to send a message to it from java, in a manner like:
FacesContext.getCurrentInstance().addMessage(arg0, arg1);
which is sent to h:messages, but to a specific id in a specific form.
How can I do this? (Without implementing validation bean or validation method - meaning without throwing validation exception).
You need to provide the so called client id, which you'll find on UIComponent.
The following is a quick example of how to use this.
Consider the following bean:
#ManagedBean
#RequestScoped
public class ComponentMsgBean {
private UIComponent component;
public UIComponent getComponent() {
return component;
}
public void setComponent(UIComponent component) {
this.component = component;
}
public String doAction() {
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(component.getClientId(), new FacesMessage("Test msg"));
return "";
}
}
being used on the following Facelet:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:body>
<h:form>
<h:outputText id="test" value="test component" binding="#{componentMsgBean.component}"/>
<h:message for="test"/>
<h:commandButton value="click me" action="#{componentMsgBean.doAction}" />
</h:form>
</h:body>
</html>
This will add a Faces message with content "Test msg" for the outputText component used in the example.
Another way to do that is: give an ID to the form, like "form1", then, when add the message, the clientId is "form1:test".