Dynamically call method in EL, which is evaluated from a String - jsf

i have a submit button. This submit button has an "action" attribute. But this action attribute should always call another function (some kind of generic). So i want to call a function dynamically. This is because i need to reuse this component. I just don't know which Type the action attribute needs (Method, String, etc. ?) and how to refer correctly to the wanted "BeanWithMethodToCall".
#Named
#SessionScoped
public class BeanWithMethodToCall{
#Inject
private BeanWhichIsCalledFromEL elBean;
public void methodToCall(){
//do something
}
public void someLogic(){
// here the wanted method is set on the bean which is later on called from el
elBean.setMethodToCall("methodToCall");
}
}
#Named
#SessionScoped
public class BeanWhichIsCalledFromEL{
// i don't know the correct type of this :S
private String method;
public void setMethodToCall(String method){
this.method = method;
}
// i don't know the correct return type of this :S
public String getMethodToExecute(){
//this method is called in the action attribute in the xhtml
// and should return a dynamic function to call
}
}
In EL:
<h:commandButton value="Cancel" action="#{beanWhichIsCalledFromEL.getMethodToExecute()}">
<f:ajax render="#form"/>
</h:commandButton>
This seems tricky.. I hope somebody can help me. Do i need Reflection ? or an EL Resolver or anything else ??

Use the brace notation #{bean[foo]} to evaluate "dynamic" method and property names.
Your specific case can be solved as below:
<h:commandButton ... action="#{bean[bean.methodToExecute]}">
See also:
Dynamic ui include and commandButton

Related

EL expression in JSF f:param name attribute

I tried the following:
Something like the facelet I used:
...
<h:button value="x" outcome="nextpage">
<f:param name="#{myBean.PARAM_NAME}" value="someValue"/>
</h:button>
...
Something like the managed bean I used as a controller for the previous facelet:
#Named(value="myBean")
#ViewScoped
public MyBean implements Serializable
{
private static final String PARAM_NAME = "paramName";
public String getPARAM_NAME()
{ return PARAM_NAME };
#PostConstruct
public void init()
{
String passedParamValue = (String) FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get(
PARAM_NAME );
...
}
}
The advantage of this is : I use the param name in two places. In the facelet and in the managed bean as well. This two places are separated. I sould use constants to reduced the possibility of the mistyping. But it seems the name of the f:param does not evaluate EL expressions. (passedParamValue is always null). But if I directly wire the text 'paramName' to the name attribute, it works fine. Am I right or is there any way to use constants here?

Pass a method expression to a custom component

I'm looking for a minimal example on how to pass a method expression to a custom component. I tried the following, but the responsible setter of my component is never called.
Bean for my view:
public String bar(){
//do stuff
return "";
}
My view:
<my:comp foo="#{bean.bar}" />
Bean for my component:
private static final String FOO = "foo";
public void setFoo(MethodExpression me){
//never called
getStateHelper().put(FOO, me);
}
public MethodExpression getFoo(){
//actually gets called
return (MethodExpression) getStateHelper().get(FOO);
}
Inside my component renderer, I call component.getFoo() and get a NPE.
You need to implement the ActionSource2 interface:
#FacesComponent(MyComponent.COMPONENT_TYPE)
public class Mycomponent extends UIComponentBase implements ActionSource2 {
// ...
}
Or, easier, to extend from UICommand class (which are also used by <h:commandXxx> components) which has all of those ActionSource2 methods already implemented the right way so that you don't need to repeat the job:
#FacesComponent(MyComponent.COMPONENT_TYPE)
public class Mycomponent extends UICommand {
// ...
}
Either way, you can use action="#{some method expression}" and even attach actionlisteners on it. Note that you can't rename the attribute name action. It really has to be action.
An open source example of such a custom component is the OmniFaces <o:commandScript>. The source code is available here.

jsf menuitem does not set property

i try to set normal property by menu-item, but it is does not work.
jsf:
<p:menuitem value="Names"
url="/master.xhtml"
action="#{navigation.name}">
<f:setPropertyActionListener target="navigation.name"
value="Billy" />
</p:menuitem>
ManagedBean:
#ManagedBean(name="navigation")
#SessionScoped //
public class LinksNavigation {
public LinksNavigation() {
super();
this.milchFleisch = "./menuFleisch.xhtml";
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name= name;
}
}
But it does not work. I dont set with "f:setPropertyActionListener"
value = "Bully". How can i set property Value by menuItem??
Thanks
In setPropertyActionListeneryou have a String instead of an EL expression. Change
target="navigation.name"
to
target="#{navigation.name}"
Also, you need to take a closer look to at the tag documentation for p:menuitem. The attribute action is expecting a method expression. You will get a MethodNotFoundException with the way your code is set up. You need to change
action="#{navigation.name}"
to
action="#{navigation.getName}"
The abbreviated syntax #{navigation.name} is used for value expressions.
You are mixing navigation methods. You cannot have the attributes url and action together for the same p:menuItem. When I tested your code action and setPropertyActionListener were never called when url was present. This behavior suggest that you have to pick one or the other.
COMMENT
Based on your sample, I think you should rethink your approach. Let's pretend for a moment that you decided not to use url="/master.xhtml" and let's go over the sequence of events. After you press the menu item, the expression #{navigation.name} in setPropertyActionListener will first set the value "Billy" to your name property (e.g. navigation.setName("Billy")). Then the expression #{navigation.getName} in the attribute action will call getName(). Now action will have the String value "Billy" and it will try to navigate to Billy.xhtml (assuming no navigation rules in faces-config and you have JSF 2.0). If that's the behavior you're after or if you have rules set up in faces-config and you are not hardcoding the value than that's another story entirely. Just keep this in mind.

JSF Reset a property of ViewScoped bean back to initial value after render

I have a ViewScoped ManagedBean. This bean has a boolean attribute which controls whether a datatable should be displayed. See below:
<p:dataTable value="#{loc.locationRows}" var="obj" ... rendered="#{loc.renderLocationTable}">
<p:column>
...
</p:column>
...
</p:dataTable>
My ManagedBean looks like this:
#ManagedBean(name = "loc")
#ViewScoped
public class LocationController implements Serializable {
private boolean renderLocationTable = false;
// JSF ActionListener.
public void methodA() {
if(someCondition) {
renderLocationTable = true; // this is the only time we should render location table
}
}
}
As soon as methodA() gets called and some condition is met, then the table should be rendered; and this works fine. But, the problem is this, for each and every other JSF ActionListener method which gets called, I have to explicitly set the rendered boolean back to false. See below:
#ManagedBean(name = "loc")
#ViewScoped
public class LocationController implements Serializable {
private boolean renderLocationTable = false;
// JSF ActionListener.
public void methodA() {
if(someCondition) {
renderLocationTable = true; // this is the only time we should render location table
}
}
// JSF ActionListener.
public void methodB() {
renderLocationTable = false;
}
// JSF ActionListener.
public void methodC() {
renderLocationTable = false;
}
}
I've given a very small snippet of the actual ManagedBean and XHTML file. In-reality, these files are huge and lot's of stuff is happening with several other boolean "rendered" flags. It is becoming increasingly difficult to keep these flags accurate. Plus, each ActionListener method now has to know about all boolean flags even if they are not related to the business at-hand.
This is what I'd love to be able to do:
<f:event type="postRenderView" listener="#{loc.resetRenderLocationTable}" />
<p:dataTable value="#{loc.locationRows}" var="obj" ... rendered="#{loc.renderLocationTable}">
<p:column>
...
</p:column>
...
</p:dataTable>
Then, in the ManagedBean have a method:
public void resetRenderLocationTable(ComponentSystemEvent event) {
renderLocationTable = false;
}
Wouldn't this be nice? No more playing games with resetting boolean variables. No more test cases where we need to make sure the table doesn't get displayed when it shouldn't be. The rendered flag can be set to true when the appropriate JSF ActionListener method sets it to true and then the "post-back" call will reset the flag back to false...Perfect. BUT, apparently there's no way of doing this out-of-the-box with JSF.
So, does anyone have a solution to this issue?
Thanks!
By the way, this situation happens probably a lot more than you think. Anytime you have a form with several commandButtons using ActionListeners, then this situation could happen to you. If you've ever had a JSF ManagedBean and you find yourself setting boolean flags to true or false scattered through-out the class, then this situation applies to you.
You didn't added primefaces tag, but according to your code I see that you are using Primefaces. A suppose your methodA() is called from, for example p:commandButton. I suggest first to create primefaces remote command:
<p:remoteCommand name="resetRenderLocationTable">
<f:setPropertyActionListener value="#{false}" target="#{loc.renderLocationTable}"/>
</p:remoteCommand>
this will create JavaScript function named resetRenderLocationTable whose call will generate AJAX request which will set renderLocationTable property to false. Now just add call to that function in oncomplete of you commandButton (or any other AJAX source):
<p:commandButton action="#{loc.methodA()}" update="myDatatable" oncomplete="resetRenderLocationTable()"/>
In next request you don't have to worry about resetting this property, just update your datatable.

Difference between value and binding

What is the difference between using value and binding with JavaServer Faces, and when would you use one as opposed to the other? To make it clearer what my question is, a couple of simple examples are given here.
Normally with JSF in the XHTML code you would use "value" as here:
<h:form>
<h:inputText value="#{hello.inputText}"/>
<h:commandButton value="Click Me!" action="#{hello.action}"/>
<h:outputText value="#{hello.outputText}"/>
</h:form>
Then the bean is:
// Imports
#ManagedBean(name="hello")
#RequestScoped
public class Hello implements Serializable {
private String inputText;
private String outputText;
public void setInputText(String inputText) {
this.inputText = inputText;
}
public String getInputText() {
return inputText;
}
// Other getters and setters etc.
// Other methods etc.
public String action() {
// Do other things
return "success";
}
}
However, when using "binding", the XHTML code is:
<h:form>
<h:inputText binding="#{backing_hello.inputText}"/>
<h:commandButton value="Click Me!" action="#{backing_hello.action}"/>
<h:outputText value="Hello!" binding="#{backing_hello.outputText}"/>
</h:form>
and the correspondibg bean is called a backing bean, and is here:
// Imports
#ManagedBean(name="backing_hello")
#RequestScoped
public class Hello implements Serializable {
private HtmlInputText inputText;
private HtmlOutputText outputText;
public void setInputText(HtmlInputText inputText) {
this.inputText = inputText;
}
public HtmlInputText getInputText() {
return inputText;
}
// Other getters and setters etc.
// Other methods etc.
public String action() {
// Do other things
return "success";
}
}
What practical differences are there between the two systems, and when would you use a backing bean rather than a regular bean? Is it possible to use both?
I have been confused about this for some time, and would most appreciate having this cleared up.
value attribute represents the value of the component. It is the text that you see inside your text box when you open the page in browser.
binding attribute is used to bind your component to a bean property. For an example in your code your inputText component is bound to the bean like this.
#{backing_hello.inputText}`
It means that you can access the whole component and all its properties in your code as a UIComponent object. You can do lot of works with the component because now it is available in your java code.
For an example you can change its style like this.
public HtmlInputText getInputText() {
inputText.setStyle("color:red");
return inputText;
}
Or simply to disable the component according to a bean property
if(someBoolean) {
inputText.setDisabled(true);
}
and so on....
Sometimes we don't really need to apply the value of UIComponent to a bean property. For example you might need to access the UIComponent and work with it without applying its value to the model property. In such cases it's good to use a backing bean rather than a regular bean. On the other hand in some situations we might need to work with the values of the UIComponent without any need of programmatic access to them. In this case you can just go with the regular beans.
So, the rule is that use a backing bean only when you need programmatic access to the components declared in the view. In other cases use the regular beans.

Resources