Pass parameters to messages from resource bundle to components other than **h:outputFormat** - jsf

Is there a convenient way to pass parameters to messages from resource bundle to components other than h:outputFormat?
For instance, this is legal:
<h:outputFormat value="#{myBundle['parametricMessage']}">
<f:param value="#{myBundle['someParameterValue']}"/>
</h:outputFormat>
But I need it for a button, like this (which won't work):
<h:commandButton value="#{myBundle['parametricMessage']}">
<f:param value="#{myBundle['someParameterValue']}"/>
</h:commandButton>
Of course, I can use link instead of button, and I can make it through a property in a managed bean, but in this question I'm seeking for a convenient way to use the button...
I'm using RichFaces 3.3.3, JSF2, facelets.

How about this approach ?
EL expression allow you to define a function .You first define a EL expression 's function , which accepts a resource bundle , its message key and placeholder 's parameter and output the resolved message .
public static String geti18nMsg(ResourceBundle bundle ,String msgKey, String paramValue ) {
String msgValue = bundle.getString(msgKey);
MessageFormat messageFormat = new MessageFormat(msgValue);
Object[] args = {paramValue};
return messageFormat.format(args);
}
Then call this function to get the resolved message in the <h:commandButton> :
<h:commandButton value="#{f:geti18nMsg(myBundle , parametricMessage, someParameterValue)}"/>

Try this:
<h:commandButton>
<h:outputFormat value="#{myBundle['parametricMessage']}">
<f:param value="#{myBundle['someParameterValue']}"/>
</h:outputFormat>
</h:commandButton>
Btw, this does what you want and also avoids having to write backing bean code.

Well I didn't find good answer on that, so the question will remain open.
A good practice I've discovered, is to have a special class that represents each resource bundle (that has parametric stuff), and to transfer all the message formation, and working with context there (like, acquire locale from FacesContext, get a ResourceBundle, apply parameters, etc). And finally to provide access to a singleton of such service class from your ManagedBean.
This requires some additional work to be done, but solves the problem and is worth of the time.

Related

Why am I able to bind <f:actionListener> to an arbitrary method if it's not supported by JSF?

I'm using Glassfish 3.1.2.2 and JSF Mojarra 2.1.6.
I have the following Facelets page:
<h:form>
<h:commandLink value="link">
<f:actionListener binding="#{backingBean.someMethod(1)}"/>
</h:commandLink>
</h:form>
And the following backing-bean:
#RequestScoped
#ManagedBean
public class BackingBean {
public void someMethod(int i) {
System.out.println("It was called: " + i);
}
}
When I click the link, "Info: It was called: 1" appears in the console.
The documentation for binding reads:
Library: http://xmlns.jcp.org/jsf/core, http://java.sun.com/jsf/core (Jsf Core)
Tag: actionListener
binding
Value binding expression that evaluates to an object that implements javax.faces.event.ActionListener. [emphasis mine]
Also, the accepted answer to this question states that it's not possible for an f:actionListener to call an arbitrary method.
Why is the backing bean method called if this isn't supported?
This is the consequence of the new EL 2.2 feature of calling a method in a value expression via the #{bean.method()} syntax instead of only referencing a property via the #{bean.property} syntax (which should indeed be of the exact type ActionListener). It wouldn't have worked in EL 2.1 or older and it would also not work when you remove the arguments and the parentheses. That document was written when EL 2.2 didn't exist (it's actually not modified as compared to JSF 1.2 version from May 2006; EL 2.2 was introduced December 2009). I however do agree that it needs an update on that part as it's confusing to starters.
The answer you found made its points based on the document, but the answerer however didn't seem to realize based on the question that while binding="#{testController.nodeListener}" failed, the binding="#{testController.nodeListener(event)}" actually worked. This only doesn't give you the opportunity to pass the ActionEvent. The answer was better if it suggested to just use binding="#{testController.nodeListener()}" instead and grab the event information in other way, such as by calling UIComponent#getCurrentComponent() or even by passing #{component} as argument. Only if you really need to have a hand of it, of course.
<h:commandLink value="link">
<f:actionListener binding="#{bean.someMethod(component)}"/>
</h:commandLink>
public void someMethod(UIComponent component) {
System.out.println("It was called on: " + component); // HtmlCommandLink
}
See also:
Invoke direct methods or methods with arguments / variables / parameters in EL
Difference between JSP EL, JSF EL and Unified EL
Differences between action and actionListener

Primefaces commandButton: f:attribute does not work

Project uses Spring Webflow and JSF (PrimeFaces). I have a p:commandButton with f:attribute
<p:commandButton disabled="#{editGroupMode=='edit'}" action="edit_article_group" actionListener="#{articleGroupManager.setSelectedRow}" ajax="false" value="Edit">
<f:attribute name="selectedIndex" value="${rowIndex}" />
</p:commandButton>
Backend code (Spring injected bean):
#Service("articleGroupManager")
public class ArticleGroupManagerImpl implements ArticleGroupManager{
public void setSelectedRow(ActionEvent event) {
String selectedIndex = (String)event.getComponent().getAttributes().get("selectedIndex");
if (selectedIndex == null) {
return;
}
}
}
The attribute "selectedIndex" is always null. Anybody knows what happened here? Thank you.
The variable name "rowIndex" suggests that you've declared this inside an iterating component, such as <p:dataTable>.
This is then indeed not going to work. There's physically only one JSF component in the component tree which is reused multiple times during generating HTML output. The <f:attribute> is evaluated at the moment when the component is created (which happens only once, long before iteration!), not when the component generates HTML based on the currently iterated row. It would indeed always be null.
There are several ways to achieve your concrete functional requirement anyway. The most sane approach would be to just pass it as method argument:
<p:commandButton value="Edit"
action="edit_article_group"
actionListener="#{articleGroupManager.setSelectedRow(rowIndex)}"
ajax="false" disabled="#{editGroupMode=='edit'}" />
with
public void setSelectedRow(Integer rowIndex) {
// ...
}
See also:
JSTL in JSF2 Facelets... makes sense?
How can I pass selected row to commandLink inside dataTable?
Unrelated to the concrete problem, I'd in this particular case have used just a GET link with a request parameter to make the request idempotent (bookmarkable, re-executable without impact in server side, searchbot-crawlable, etc). See also Communication in JSF 2.0 - Processing GET request parameters.

UIComponent#getValue() obtained via binding is not available in validator of another component

I'm trying to figure out why an f:attribute tag's value isn't passed when attached to h:inputSecret tag. I'm quite new to jsf, but as far as I know attributes can be attached to any kind of component. Here is the code:
<h:inputSecret id="passw" value="#{advertAdder.userPass}"
required="true" validator="#{advertAdder.validatePasswords}">
<f:attribute name="confirmedPass" value="#{advertAdder.passConfirmator.value}"/>
</h:inputSecret>
<h:inputSecret id="passwConfirm" required="true"
binding="#{advertAdder.passConfirmator}"/>
and the method that wants to acces this attribute:
public void validatePasswords(FacesContext context, UIComponent component, Object value)
{
if (!value.equals(component.getAttributes().get("confirmedPass")))
{
FacesMessage mess = new FacesMessage("Password and it's confirmation are not the same!");
context.addMessage(component.getClientId(context), mess);
((UIInput) component).setValid(false);
}
}
In above code component.getAttributes() always returns map with only two attributes:
javax.faces.component.VIEW_LOCATION_KEY and com.sun.faces.facelets.MARK_ID.
I've added attribute tag to a h:commandButton to check it, and then everything was fine. Am I missing something or it's not possible to add an attribute to non-action tag?
I'm using Mojarra 2.0.2 and Glassfish 3.0.1.
Thanks in advance.
Input components are processed in the order as they appear in the component tree. The UIInput#getValue() is only available when the component is already been processed. Otherwise you need to use UIInput#getSubmittedValue() instead.
<f:attribute name="confirmedPass" value="#{advertAdder.passConfirmator.submittedValue}"/>
Note that this gives you the unconverted and unvalidated value back. It would make somewhat more sense to put the validator on the confirm password field instead and pass the value of the first password field along. See also JSF Validator compare to Strings for Equality and JSF doesn't support cross-field validation, is there a workaround?
Alternatively, you can also try out the OmniFaces <o:validateEqual> component. You can find a concrete example in this article.
Unrelated to the concrete problem, it's unnecessary to bind the component to the bean this way. Replace all occurrences of #{advertAdder.passConfirmator} by #{passConfirmator}. Keep the controller free of properties which are never internally used.

Jsf dynamically created actionListener parameter

I have a custom facelet component (custom tag) but there is one thing that currently annoys me a lot. I'm trying to pass an action listener as a parameter to the custom tag, in order to make it more dynamic and just doesn't work.
Environment: JSF 1.2, IceFaces 1.8
Here's the way I'm trying to achieve this:
the command link uses the passed parameter 'paginationController'
<h:commandLink id="#{id}-link-three" value="click"
actionListener="#{paginationController.paginationLinkClicked}" />
the parameter 'paginationController' is passed like this:
paginationController="rowSelectController"
when I click the link, there's what I receive:
Received 'javax.el.MethodNotFoundException' when invoking action listener
'#{paginationController.paginationLinkClicked}' for component 'entity-list-apps-link-three'
2011-02-22 12:49:47,803 SEVERE [javax.faces.event] (http-127.0.0.1-8080-4)
javax.el.MethodNotFoundException: /WEB-INF/jsf/common/components/facelets
/applicationList.xhtml #107,71 actionListener="#{paginationController.paginationLinkClicked}":
Method not found: rowSelectController.paginationLinkClicked(javax.faces.event.ActionEvent)
So it seems that it successfully resolves the bean name to rowSelectController, but it complaints it can't find the method, and the method IS there!
One more thing, if I replace the parameter with the correct controller's name, it just works! Any ideas?
Because paginationController is variable you need to use the [] syntax here. Assuming paginationLinkClicked is a fixed method name:
<h:commandLink actionListener="#{paginationController['paginationLinkClicked']}" />
If paginationLinkClicked would also be variable, you need to omit the single quotes:
<h:commandLink actionListener="#{paginationController[paginationLinkClicked]}" />

Valuechangelistener Doubt in JSF

HI,
Please see the following code:
<h:selectOneMenu id="countries" value="#{countryBean.selectedCountry}" onchange="submit()
valueChangeListener="#{countryBean.changeCountry}">
<f:selectItems value="#{countryBean.countries }" />
</h:selectOneMenu>
Backing Bean
public void changeCountry(ValueChangeEvent event){
String newValue = (String)event.getNewValue();
String oldValue = (String)event.getOldValue();
System.out.println("New Value : " + newValue);
System.out.println("Old Value : " + oldValue);
if ("1".equals(newValue)){
this.countries = new ArrayList<SelectItem>();
this.cities.add(new SelectItem("1","Delhi"));
this.cities.add(new SelectItem("2","Mumbai"));
}
if ("2".equals(newValue)){
this.cities = new ArrayList<SelectItem>();
this.cities.add(new SelectItem("1","Mossco"));
}
}
Please let me know if the implementation is correct. It is working fine.
My questions are:
What is the advantage of adding the f:valueChangeListener tag inside the h:selectOneMenu tag. I have used the normal attribute valueChangeListener="#{countryBean.changeCountry}".
Is it necessary to use onchange="submit() this code to change the values.
What is difference between writing the custom listeners by implementing the ActionListener interface and just using the attribute in the UIComponent tags (action="methodName").
Please explain me.
The ValueChangeListener will only be called when the form is submitted, not when the value of the input is changed. Thus, if you want to run this listener when the value is modified, you have two solutions:
Submit your form when the onchange event is fired (this is what you did in your code);
Use an Ajax call instead, by using some dedicated components (already integrated in JSF2, with <f:ajax>, or third-parties libraries such as Richfaces, Primefaces...).
Here is an example with Richfaces:
<h:selectOneMenu id="countries" value="#{countryBean.selectedCountry}" valueChangeListener="#{countryBean.changeCountry}">
<a4j:support event="onchange" .../>
<f:selectItems value="#{countryBean.countries }" />
</h:selectOneMenu>
Regarding the code of your listener, it seems correct, but why question is why do you need a ValueChangeListener here? Indeed, this listener is usefull when you want to track a modification of a value. That's why the ValueChangeEvent provides both getOldValue() and getNewValue() methods.
In your code, you do not care about the old value, so basically, you could "simply" do an action instead of a valueChangeListener (ex. with Richfaces):
<h:selectOneMenu id="countries" value="#{countryBean.selectedCountry}">
<a4j:support event="onchange" actionListener="#{countryBean.changeCountry}"/>
<f:selectItems value="#{countryBean.countries }" />
</h:selectOneMenu>
Finally, regarding the difference between the valueChangeListener attribute and <f:valueChangeListener> is that the first binds a Java method (#{myBean.myMethod}), while the second binds a Java class (type="com.foo.MyListenerClass") which implements the ValueChangeListener interface. So the second one could be more generic than the first one...
Romaintaz already pointed out the most, I just wanted to get straight on your concrete questions:
What is the advantage of adding the f:valueChangeListener tag inside the h:selectOneMenu tag. I have used the normal attribute valueChangeListener="#{countryBean.changeCountry}".
As Romaintaz said, the attribute points to a method and the f: tag points to a class. Another advantage is that you can have multiple of them, whenever that is necessary.
Is it necessary to use onchange="submit() this code to change the values.
That Javascript doesn't change the values. That Javascript submits the entire form without the need to pressing the submit button yourself, whenever the value has been changed by the enduser. No, that is not necessary. You can also just remove it and expect that the enduser presses the submit button himself. Once again, that JavaScript is not part of JSF.
What is difference between writing the custom listeners by implementing the ActionListener interface and just using the attribute in the UIComponent tags (action="methodName").
This question is already asked before: difference between action and actionlistener.
The solution from romaintaz of calling an action instead of valueChangeListener is also great because in the case of "change" event the action is called after the model is updated (allowing for a DB update for example) while the valueChangeListener is called before....

Resources