How to use b:growl - jsf

I'm trying to show a specific b:growl element loaded from a bean, basically I'm try to replicate the example from the BootsFaces showcase (https://showcase.bootsfaces.net/forms/Growl.jsf;jsessionid=QdtXGdUxPK9sS714iLGuyksK93AMfZM-WfZm3py_.showcase01).
I used FacesMessages.info, but I get two b:growl messages. So, how can I target the specific b:growl element to show my message?
In the example from showcase: What does the messagesBean.specificInfo method do?
Edit:
Thank you Stephan, but is not working for me, I still get two b:grolw messages and the one width globalOnly="true" is ignored and a standar one is showed instead.
Here is my code:
xhtml:
<ui:define name="content">
<div class="container" style="width: auto">
<h:form id="idForm">
<b:panel title="#{msg['administrarServicio']}" look="primary"
id="panel" collapsible="false">
<b:commandButton id="idBorrar" col-lg="3" col-md="3" colSm="10"
col-xs="10" offset-lg="2" offset-md="2" offset-sm="1"
offset-xs="1" value="Borrare o o o o" look="danger"
iconAwesome="trash" iconAlign="right"
action="#{serviceManagementBean.borrar}" />
</b:panel>
<b:growl id="growlCommonMsg" placementFrom="bottom"
show-detail="true" show-summary="true" allowDismiss="true"
global-only="true" delay="10000" escape="true" />
<b:growl for="idBorrar" id="growlMsg" globalOnly="true"
placementFrom="bottom" show-detail="true" show-summary="true"
allowDismiss="true" delay="10000" escape="true" global-only="false"
animation-enter="animated bounceInDown"
animation-exit="animated flipOutX" />
</h:form>
</div>
</ui:define>
Java:
public void borrar() {
System.out.println("BORRAR " + this.idTramite);
FacesMessages.info("idForm:idBorrar", "Se boró correctamente el servicio " + this.idTramite, "Nunca va a volver. ¡Nunca!");
}

Let's begin with the source code you're missing. Here you go:
public void specificInfo() {
FacesMessages.info("growlForm:ref", "Info", "This is a specific message!");
}
public void error() {
FacesMessages.error("Error!", "Something has gone <strong>wrong</strong>.");
}
You'll notice the only difference is the number of parameters. specificInfo() includes the id growlForm:ref. You didn't include it with your code snippet, but growlForm is the id of the surrounding form (at least in our showcase). The second part of the id, ref, indicates that the FacesMessage is to be displayed by an <h:message>, <b:message>, <p:message>, <p:growl> or <b:growl> which is defined inside this form and bears the attribute for="ref".
Looking at the two <b:growl>s of the showcase, you'll see that the first growl doesn't have a for attribute. Instead, it sets globalOnly="true". This causes the growl to ignore every FacesMessage bearing an id. It'll ignore the messages generated by specificInfo().
So that's why there are two <b:growl>s in our showcase example, but every user action only triggers one of them.
There's that. Your issue is the other way round: One <b:growl> displays two growl elements on the screen. You haven't provided any Java source code (yet?), so I can only guess. The most likely explanation is that you're really generating the FacesMessage twice. I recommend setting a breakpoint in your debugger (or adding a System.out.println(), if you prefer that approach) to rule that out.
I hope I've given you enough clues to solve your issue. If not, don't hesitate to reach out to us on our bug tracker on GitHub. Please include the link to this StackOverflow question, so I can update this answer if necessary.

Related

Using findComponent on preRenderView listener

On the JSF page:
<f:event type="preRenderView" listener="#{backingBean.test()}" />
<h:inputHidden id="inputHiddenId" value="dummy" />
On the backingBean:
public void test() {
System.out.println("test");
FacesContext fc = FacesContext.getCurrentInstance();
UIComponent comp = fc.getViewRoot().findComponent("inputHiddenId");
if (comp != null) {
System.out.println("comp " + comp); // Does not print
}
}
The phaseListener shows that test() is called during render response phase:
START PHASE RESTORE_VIEW 1
END PHASE RESTORE_VIEW 1
START PHASE RENDER_RESPONSE 6
test
END PHASE RENDER_RESPONSE 6
However, it is not finding the inputHiddenId component. It seems that the component is not available during this time. Does it need to be on a postback? How can I access the component when first loading the page? Sorry, I am not too familiar with the intricacies of the JSF lifecycle. If anyone could shed some light on this, it would be greatly appreciated.
Reposting the problem:
The real problem is that I have a form with several fields. After the form is submitted, users can still edit certain fields which has the effect of resetting other sections on the form and making it invalid. Since it is a long form, users should be able to save the form even though it fails validation, and return to it later. So when loading the page, I'd like it to display inline validation on the fields. We are using JBoss Seam. The validation method displays the errors using
StatusMessages.instance().addToControl("inputHiddenId", severity, message)
The validation method is called from the page.xml using
<action execute="#{backingBean.pageInitWithValidation()}" on-postback="false" />
However this doesn't display the error message inline on the ui component
<s:div id="errorMessages">
<h:inputHidden id="inputHiddenId" value="dummy" />
<h:messages for="inputHiddenId" />
</s:div>
It shows it instead at the top in the global messages
<h:messages globalOnly="true" />
That's why I tried to use the preRenderView, but that had the same effect.
I'm currently using a second method with the body onload event along with a4j:jsFunction, but it is not very clean.
<a4j:jsFunction name="validate"
action="#{backingBean.validate()}" render="formId" />
<h:body onload="validate()">

Primefaces won't call setter on ManagedBean

I'm in the middle of building a web application (Spring 4, Primefaces 5.1 and JPA).
While one of my xhtml-pages has no problems working with its ManagedBean, the others won't really work. To be more specific, the UI input components (like inputText) won't call any setters from the managed Beans.
I've already run my Tomcat (8) on debug mode, which showed me that the page calls the get-methods, but no set-methods at all. If I try to persist something, all values are null (or 0, in case of an int-value). (it even persists an object into the database with all values null, though I have declared some #NotNull constraints which should be taken to the database configuration via JPA)
So, question is: How can I make my inputFields work with the fields of my ManagedBean? (Eclipse also shows me in the editor, that theoretically, the connection to the fields is there, it knows the managed bean, the field and the get-/set-methods)
SoftwareManagedBean.java
#ManagedBean(name = "swmb")
#ViewScoped
public class SoftwareManagedBean extends AssetManagedBean implements
Serializable {
private String bezeichnung;
private Software neueSoftware;
// +some more private fields, every single one with its get-/set-method
#Override
public String getBezeichnung() {
return super.getBezeichnung();
}
#Override
public void setBezeichnung(final String bezeichnung) {
super.setBezeichnung(bezeichnung);
}
//instantiante the field "neueSoftware"
public void createEmptySoftware(){
if(neueSoftware != null)
return;
this.neueSoftware = new Software();
}
//Persist Software with values from inputFields
public void addSoftware() {
createEmptySoftware();
neueSoftware.setBezeichnung(getBezeichnung());
softwareService.addSoftware(neueSoftware);
//...
neueSoftware = null;
}
viewSoftware.xhtml
<h:body>
<p:dialog header="Neue Software anlegen" widgetVar="SwNeuDialog" width="60%"
closeOnEscape="true" draggable="false" resizable="false" position="center">
<h:form id="SwDlgForm">
<h:panelGrid columns="3" border="0" >
<p:outputLabel for="swBezeichnung" value="Bezeichnung: " />
<p:inputText id="swBezeichnung" value="#{swmb.bezeichnung}"
label="Bezeichnung" required="true" />
<f:verbatim/>
<p:outputLabel for="swKategorie" value="Kategorie: " />
<p:selectOneMenu id="swKategorie" value="#{swmb.kategorie}" label="Kategorie" required="true" >
<f:selectItem itemLabel="Kategorie wählen" value="#{null}" noSelectionOption="true"/>
<f:selectItems value="#{swmb.kategorieListe}" var="kat" itemLabel="#{kat.bezeichnung}" itemValue="#{kat}"/>
</p:selectOneMenu>
<p:commandButton value="neue Kategorie hinzufügen" />
<!-- + some more input fields -->
<p:commandButton value="Speichern" action="#{swmb.addSoftware()}" onclick="PF('SwNeuDialog').hide()" resetValues="true" process="#this"/>
<p:commandButton value="Abbrechen" onclick="PF('SwNeuDialog').hide()" resetValues="true" process="#this"/>
</h:panelGrid>
</h:form>
</p:dialog>
<!-- dataTable -->
</h:body>
AssetManagedBean.java
#ManagedBean
public abstract class AssetManagedBean {
//name of the hard-/software
private String bezeichnung;
//+ some more fields with get-/set methods
public String getBezeichnung() {
return bezeichnung;
}
public void setBezeichnung(String bezeichnung) {
this.bezeichnung = bezeichnung;
}
I hope that code is sufficient to see the problem, since the rest of the code follows the same structure. I think, the problem could lie within the xhtml file, but I don't see where or why. I've got the SpringBeanFacesELResolver (or however it is called), I've already looked through the code and compared it to another xhtml page and its Managed Bean, but there are no differences anymore. (though one is working, one not)
My debugger showed, how the working class/page (viewAdministration.xhtml) called the get-/set methods of the managed bean:
opening dialog window: get...(), set...()
clicking the commandButton to submit/persist: get() (old Value), set() (new Value), get() (new Value)
Another get() (called by the add... method)
(+ another get() for the dataTable on the main page)
on viewSoftware.xhtml, it looks like this:
opening dialog window: get()
clicking the commandButton to submit/persist:
another get() called by the addSoftware method
As you can see, when I try to submit, there is no set or get.
So, to summarize:
no setter called by trying to submit
the code on viewSoftware.xhtml and SoftwareManagedBean is similar to another, functioning ManagedBean + xhtml page (I've compared it again and again)
annotations in Managed Beans are the same (#ManagedBean, #ViewScoped)
the inputFields are inside a form (
I'm totally clueless, but I think it is some small mistake from my side that I can't just see.
I've searched through the web and especially stackoverflow, but all the problems and answers I've found couldn't help me finding what's wrong
Even without inheriting from a superclass it won't work (tried that out too)
I hope, you can help me. If this post is lacking some information, I'm sorry about that, I tried my best to not let this post grow too big and still get as much relevant information in it as possible.
So, I have found my mistake (or at least, I think I have). Only took me 2 weeks, but anyway...
I tried to test it out more specifically, wrote test classes and an xhtml page. Nothing worked (from simple Input over Dates to own classes).
The solution to this problem was to disable ajax on my commandButton (ajax="false"). When I tried to understand more of it, I realized that the commandButton opening the dialog window was nested in a facet inside a dataTable, and thus it had problems to properly set the values of the input fields.
So, thank you for your help. Maybe/hopefully this can or will help some other people later as well.
From the first glance at the code, without reading it whole, try putting process="SwDlgForm" on your command buttons, instead of process="#this". If that doesn't solve the problem, I'll read more carefully and try to help.

Is there a way to create dynamically <rich:tab> elements?

Let say that I want to create a variable set of <rich:tab> elements within a <rich:tabPanel> component. So I tried to do that way:
<rich:tabPanel switchType="client" ...>
<ui:repeat value="#{myBean.myTabs}" var="tab">
<rich:tab name="#{tab.name}" label="#{tab.label}"/>
</ui:repeat>
</rich:tabPanel>
But it didn't work, as no tab is rendered. I also got the following message in the logs:
j_id174: tab panel has no enabled or rendered tabs!
This problem seems to be encountered by others people, for example here.
So as suggested by the previous thread, I replaced my <ui:repeat> by a <c:forEach> but the problem still occurs.
I have a way to solve this problem using the binding attribute of my <rich:tabPanel> component:
<rich:tabPanel switchType="client" binding="#{tabNavigationBean.tabPanel}"
</rich:tabPanel>
and then in my Java bean:
private HtmlTabPanel tabPanel; // + getter and setter
public void setTabPanel(HtmlTabPanel tabPanel) {
this.tabPanel = tabPanel;
if (tabPanel != null) {
createTabs();
}
}
private void createTabs() {
Application application = FacesContext.getCurrentInstance().getApplication();
HtmlTab newTab = null;
for (DedicatedPageTab dpt : getDedicatedPageTabs()) {
newTab = (HtmlTab) application.createComponent(HtmlTab.COMPONENT_TYPE);
newTab.setLabel(dpt.getLabel());
newTab.setName(dpt.getName());
tabPanel.getChildren().add(newTab);
}
}
This code is working.
However, my question is to know if I can solve my problem without using the binding attribute (i.e. a 100% pure XHTML solution)?
<a4j:outputPanel id="out">
<rich:tabPanel>
<c:forEach items="list" var="var">
<rich:tab label="#{var.name}" switchType="client">
content
</rich:tab>
</c:forEach>
</rich:tabPanel>
</a4j:outputPanel>
Yes, it is possible, but difficult. Here are some notes I have:
Use c:forEach to create tab tags inside tabPanel inside outputPanel. reRender outputPanel on tab removal, add, or name change
http://relation.to/11633.lace
http://devharbor.blogspot.com/2009/08/add-jsf-controls-dynamically-with.html
We also made use of templating, though I still have an outstanding issue for it: How to force the build phase in a JSF 1.2 page using JSTL?
http://facelets.java.net/nonav/docs/dev/docbook.html#template
Docs on templating
http://www.jsfcentral.com/articles/facelets_3.html
Templating tutorial

Rerendering show/hide trick with AJAX (JSF+richfaces) only work for first record in a4j:repeat

For a while now, I've been working on a JAVA-based web project, and have found this website to be very helpful on numerous occasions.
So, 'got some problems of my own now - and would appreciate if you help out!
Ok, so Here's the thing -
I'm trying to render a list of messages, each of which consists of a message title and a message body. The trick I'm working on is that the message body, for as long as the title (which is an a4j:commandLink) hasn't been clicked-on, should be hidden. And once the title's clicked - the body should be displayed. And once its clicked again - hide. And so forth.
Here's what I did at the JSF side (some parts have been omitted for simplicity):
<a4j:repeat var="msg" value="#{ForumRenderJSF.messages}">
<a4j:region id="msgAjaxRegion" renderRegionOnly="true">
<a4j:outputPanel id="msgPanel" ajaxRendered="true">
<rich:panel style="width: 100%; border: 0">
<a4j:form id="msgForm">
<!--
The message's title.
Each click results in either the revealing or hiding of the message's body.
-->
<a4j:commandLink value="#{msg.title}" action="#{ForumRenderAssistJSF.reevaluateRender}"/>
<h:outputText value=" By: <i>#{msg.userNick}</i>, #{msg.timestamp}" escape="false"/>
<!--
The message's body.
-->
<!-- A (textual) flag, indicating whether the body should be rendered. -->
<h:inputText id="renderBodyFlag"/>
<br/>
<!-- The body. -->
<a4j:outputPanel rendered="#{rich:findComponent('renderBodyFlag').value == true}">
<h:outputText value="#{msg.body}"/>
</a4j:outputPanel>
</a4j:form>
</rich:panel>
</a4j:outputPanel> <!-- msgPanel -->
</a4j:region>
</a4j:repeat>
Note the usage of:
1. A dummy "renderFlag" field (should be hidden, eventually), which value denotes whether the body should be rendered.
2. A backing bean for rendering assistance (ForumRenderAssistJSF); It goal is to flip the proper renderFlag's value from "true" to "false", and vice-versa.
3. An a4j:region to isolate each message when firing the request for ForumRenderAssistJSF.reevaluateRender() -- so that the bean can find the right "renderFlag" field.
As for the bean:
public class ForumRenderAssistJSF {
public void reevaluateRender()
{
FacesContext context = FacesContext.getCurrentInstance();
UIViewRoot root = context.getViewRoot();
UIComponent renderFlagComp = (new UIComponentLookup()).lookup(root, compLookup); // My recursive search
String renderFlagVal = (String) ((HtmlInputText)renderFlagComp).getValue();
if (!renderFlagVal.equals("true"))
{
((HtmlInputText)renderFlagComp).setValue("true");
}
else
{
((HtmlInputText)renderFlagComp).setValue("false");
}
}
}
AND THE PROBLEM IS:
The trick actually works -- but only for the first message in the list!
For the rest of them, I see that the server can reach the right renderFlag input-text component (tested by inserting values at the client), but for some reason - the client always renders it blank (no content) upon AJAX reply!
I tried digging deep inside richfaces tutorials and manuals, and to me it seems like everything is as it should be. So, I'm kind'a lost here, and as I said - would deeply appreciate your help in regards!
Thanks!
Have you tried using a rich:simpleTogglePanel? It seems to provide all the functionality you need.

How to display my application's errors in JSF?

In my JSF/Facelets app, here's a simplified version of part of my form:
<h:form id="myform">
<h:inputSecret value="#{createNewPassword.newPassword1}" id="newPassword1" />
<h:message class="error" for="newPassword1" />
<h:inputSecret value="#{createNewPassword.newPassword2}" id="newPassword2" />
<h:message class="error" for="newPassword2" />
<h:commandButton value="Continue" action="#{createNewPassword.continueButton}" />
</h:form>
I'd like to be able to assign an error to a specific h:message tag based on something happening in the continueButton() method. Different errors need to be displayed for newPassword and newPassword2. A validator won't really work, because the method that will deliver results (from the DB) is run in the continueButton() method, and is too expensive to run twice.
I can't use the h:messages tag because the page has multiple places that I need to display different error messages. When I tried this, the page displayed duplicates of every message.
I tried this as a best guess, but no luck:
public Navigation continueButton() {
...
expensiveMethod();
if(...) {
FacesContext.getCurrentInstance().addMessage("newPassword", new FacesMessage("Error: Your password is NOT strong enough."));
}
}
What am I missing? Any help would be appreciated!
FacesContext.addMessage(String, FacesMessage) requires the component's clientId, not it's id. If you're wondering why, think about having a control as a child of a dataTable, stamping out different values with the same control for each row - it would be possible to have a different message printed for each row. The id is always the same; the clientId is unique per row.
So "myform:mybutton" is the correct value, but hard-coding this is ill-advised. A lookup would create less coupling between the view and the business logic and would be an approach that works in more restrictive environments like portlets.
<f:view>
<h:form>
<h:commandButton id="mybutton" value="click"
binding="#{showMessageAction.mybutton}"
action="#{showMessageAction.validatePassword}" />
<h:message for="mybutton" />
</h:form>
</f:view>
Managed bean logic:
/** Must be request scope for binding */
public class ShowMessageAction {
private UIComponent mybutton;
private boolean isOK = false;
public String validatePassword() {
if (isOK) {
return "ok";
}
else {
// invalid
FacesMessage message = new FacesMessage("Invalid password length");
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(mybutton.getClientId(context), message);
}
return null;
}
public void setMybutton(UIComponent mybutton) {
this.mybutton = mybutton;
}
public UIComponent getMybutton() {
return mybutton;
}
}
In case anyone was curious, I was able to figure this out based on all of your responses combined!
This is in the Facelet:
<h:form id="myform">
<h:inputSecret value="#{createNewPassword.newPassword1}" id="newPassword1" />
<h:message class="error" for="newPassword1" id="newPassword1Error" />
<h:inputSecret value="#{createNewPassword.newPassword2}" id="newPassword2" />
<h:message class="error" for="newPassword2" id="newPassword2Error" />
<h:commandButton value="Continue" action="#{createNewPassword.continueButton}" />
</h:form>
This is in the continueButton() method:
FacesContext.getCurrentInstance().addMessage("myForm:newPassword1", new FacesMessage(PASSWORDS_DONT_MATCH, PASSWORDS_DONT_MATCH));
And it works! Thanks for the help!
You also have to include the FormID in your call to addMessage().
FacesContext.getCurrentInstance().addMessage("myform:newPassword1", new FacesMessage("Error: Your password is NOT strong enough."));
This should do the trick.
Regards.
Remember that:
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage( null, new FacesMessage( "The message to display in client" ));
is also valid, because when null is specified as first parameter, it is applied to the whole form.
More info: coreservlets.com //Outdated
JSF is a beast. I may be missing something, but I used to solve similar problems by saving the desired message to a property of the bean, and then displaying the property via an outputText:
<h:outputText
value="#{CreateNewPasswordBean.errorMessage}"
render="#{CreateNewPasswordBean.errorMessage != null}" />
Found this while Googling. The second post makes a point about the different phases of JSF, which might be causing your error message to become lost. Also, try null in place of "newPassword" because you do not have any object with the id newPassword.
I tried this as a best guess, but no luck:
It looks right to me. Have you tried setting a message severity explicitly? Also I believe the ID needs to be the same as that of a component (i.e., you'd need to use newPassword1 or newPassword2, if those are your IDs, and not newPassword as you had in the example).
FacesContext.getCurrentInstance().addMessage("newPassword1",
new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error Message"));
Then use <h:message for="newPassword1" /> to display the error message on the JSF page.
Simple answer, if you don't need to bind it to a specific component...
Java:
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Authentication failed", null);
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, message);
XHTML:
<h:messages></h:messages>

Resources