I've seen a lot of examples online of code where a method is called with a "f:ajax" tag but the name of the method gets shortened in the tag when the method name starts with "get". I haven't been able to find the reason for this. Below is an example of what I mean.
For instance, in the xhtml file "sayWelcome" is called:
...
<h:commandButton value="Welcome Me">
<f:ajax execute="name" render="output" />
</h:commandButton>
<h:outputText id="output" value="#{helloBean.sayWelcome}" />
...
but the method in the bean is called "getSayWelcome":
public String getSayWelcome(){
return name;
}
Why does the "get" get dropped from the method name in the "f:ajax" tag?
The JavaBeansSpecification defines the naming convention for the properties adding the get and set before the functions that acts as properties, see this article for more info.
The expression language that use JSF also complains the JavaBeans properties name convention you can check this in this article, refer to the Referring to Object Properties Using Value Expressions section.
So in conclusion when the EL (Expression language) finds a sentence as <h:outputText id="output" value="#{helloBean.sayWelcome}" /> it will try to call a getter or the setter function for the sayWelcome property, it depends if it need to assign the value (setter) or get the value (getter).
Related
index.xhtml
<p:selectOneMenu id="d2" value="#{mainManageBean.areaSelected}" >
<f:selectItem itemValue="" itemLabel="Select one" />
<f:selectItems value="#{mainManageBean.areaList}" var="area"
itemValue="#{area.id}" itemLabel="#{area.name}"/>
<p:ajax event="valueChange" listener="#{mainManageBean.changeAreaSelect()}" update="hi" />
</p:selectOneMenu>
When i have value set like this "mainManageBean.areaSelected" where areaSelected is entity from database
private Area areaSelected;
the ajax event dont work,
but when i change it to something like this "mainManageBean.s1menu" where this "s1menu" is just a normal String ajax event work fine.
What is the reason of that and how to fix it?
Edit
this is my buged converter:
#FacesConverter
public class areaConverter implements Converter{
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
// here i have problem value is id of entity and have no idea how to get this entity form this id
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
// works fine value = Area entity
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null || value.equals("")) {
return "";
} else {
return String.valueOf(((Area) value).getId());
}
}
}
Have problem with getAsObject, i have this value as id but cant get entity from it. Normaly i would use AreaFacade.find(id) but i cant use there #EJB to get it.
First of all, your <f:selectItem itemValue> is wrong. It should represent exactly the same type as <p:selectOneMenu value>, which is thus Area. Replace itemValue="#{area.id}" by itemValue="#{area}". You indeed need a Converter for this.
As to your problem with the converter,
Have problem with getAsObject, i have this value as id but cant get entity from it. Normaly i would use AreaFacade.find(id) but i cant use there #EJB to get it.
you have 2 options:
Make it a #ManagedBean #RequestScoped instead of #FacesConverter and reference it as converter="#{areaConverter}" instead of converter="areaConverter".
Install OmniFaces >= 1.6. It adds full transparent support for #EJB inside #FacesConverter without any additional configuration or annotations.
If you go the OmniFaces path anyway, then you could also just throw away your custom converter altogether and go for its builtin SelectItems(Index)Converter without the need to create any custom converter for itemValue="#{area}".
<p:selectOneMenu ... converter="omnifaces.SelectItemsConverter">
See also:
CDI Injection into a FacesConverter
You are trying to set an Entity with value of ID, I assume Integer or String? The reason why ajax does not fire is because event="valueChange" does not occur. If you tried to submit this form without ajax you would get a sweet ClassCastException. As I mentioned in my comment and Makky in his answer, change itemValue to:
<p:selectOneMenu id="d2" value="#{mainManageBean.areaSelected}" >
<f:selectItem itemValue="#{null}" itemLabel="Select one" />
<f:selectItems value="#{mainManageBean.areaList}" var="area"
itemValue="#{area}" itemLabel="#{area.name}"/>
<p:ajax listener="#{mainManageBean.changeAreaSelect()}" update="hi" process="#this />
</p:selectOneMenu>
As per comment from Kuba
<f:selectItems value="#{mainManageBean.areaList}" var="area"
itemValue="#{area.id}" itemLabel="#{area.name}"/>
change itemValue as
<f:selectItems value="#{mainManageBean.areaList}" var="area"
itemValue="#{area}" itemLabel="#{area.name}"/>
Update:
The other thing it could be the converter. My suggestion is to use the SelectItemsConverter from Onmnifaces.
Omnifaces select item converter
In JSF 2.2 (incl. CDI beans) I want to view elements of a list.
There is already a file to show a single element, let's say either a tag file or a fragment that can be included via <ui:include>.
Each element view shall use its own "backing bean". How do I implement this?
My starting point:
main.xhtml:
<t:dataList value="#{bean.elements}" var="myElement">
<ui:include src="element.xhtml">
<ui:param name="elementId" value="#{myElement.id}" />
<ui:param name="context" value="#{otherBean.context}" />
<ui:param name="callerClientId"
value="#{ ... something like "this.clientId" .. }" />
</ui:include>
</t:dataList>
element.xhtml:
<ui:fragment>
<!---
each included element.xhtml should get its own elementBean,
something like the following must happen:
"elementBean = elementBeanFactory.getOrCreate(elementId, context, callerClientId)"
--->
<h:inputText value="#{elementBean.value}"> ...
</ui:fragment>
How about:
Encapsulate your code as a composite component
Create the "beans" that you wish to use & put them in a List
Iterate over the list and render the custom component - passing in an instance of the bean
Wouldn't this solve the problem at hand?
My use case: the user choose a questionnaire in a form. When the form is submitted, a faces-flow is started to display the questions of the questionnaire.
To send the questionnaire to the flow, in the bean of the flow I inject the CDI bean of the page which contains the form.
I wonder if there are other ways to send the questionnaire to the flow. If there are several ways, what's the best one?
You can pass parameters via the form and get them in the initializer method called at the initialization of your flow.
Form (just replace the inputHidden parameter with whatever you're using to select your questionnaire)
<h:form id="myForm" prependId="false">
<h:commandLink value="Enter myFlow" action="my-flow"/>
<h:inputHidden id="parameter" name="parameter" value="8"/>
</h:form>
Flow
#Produces #FlowDefinition
public Flow defineFlow(#FlowBuilderParameter FlowBuilder flowBuilder) {
String flowId = "my-flow";
flowBuilder.id("", flowId);
flowBuilder.initializer("#{myFlowBean.startFlow()}");
...
}
Backing bean
#Named
#FlowScoped("my-flow")
public class MyFlowBean implements Serializable {
public void startFlow() {
String parameter = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("parameter");
//now do sthg with the parameter, such as fetching the questionnaire
....
}
}
See this answer for more details
Addition to "thomas.g"s helpful answer:
I had the same problem, but could not fix it with the hiddenInput approach. Despite the prependId="false" attribute my id and name of the hidden input field got changed by the primefaces p:dataTable element I used. The issue could be fixed with the f:param elemtent inside the h:commandLink element:
<h:commandLink value="Enter myFlow" action="my-flow" >
<f:param name="parameter" value="8"/>
</h:commandLink>
I hope this might be helpfull to someone with a similar problem.
This can be done in the flow xml file using the initializer tag
<initializer>
#{myFlowBean.startFlow()}
</initializer>
to call the your initialize method in the flow scoped bean
Here is my (simplified) issue :
I've got a page that is using 2 composite components of mine :
- CCSelection
- CCDisplay
In CCSelection, I have a list of values, each one has got a h:commandLink onto.
When clicking on a link, the CCDiaplay component is refreshed using the selected value.
To do this, CCSelection exposes a method attribute that is directly linked on each h:commandLink. The value is given to the method using f:attribute.
In the page backing bean, I've got a method (that is given to CCSelection as an attribute), that sets a member.
CCDisplay gets this value though an cc:attribute via the pages's member's getter.
It works !
Now, I want to ajaxize this behaviour.
I tryed to put an f:ajax for each h:commandLink in CCSelection... but if I put #form or #all in the render attribute, nothing is rendered (but the setter methods are called). If I put the id of the UIComponent (of the Page) to render, I get a nullpointerexception saying that a property is not defined for NamingContainer in CCDisplay. Quite strange because I didn't change anything inside CCDisplay !
I think the solution is to put the f:ajax not inside CCSelection but in Page.
So there may be 2 ways to achieve this :
- CCSelection raises an event f:ajax can manage... but how ?
- Using cc:clientBehaviour for CCSelection. But is it possible to target more that 1 component (I've got many h:commandLink, but I want only 1 event).
- Other ways ?
Here is a pseudo code
page.xhtml
<myComp:ccSelection actionMethod="#{pageBean.select}"
render="#{clientIDHelper.clientId['display']}" />
<h:panelGroup id="diplay" binding="#{clientIDHelper.bindings['display']}">
<myComp:ccDisplay value="#{pageBean.value}" />
</h:panelGroup>
To recover the full clientid of the panel containing the ccDiaplay composite component, I use a clientIDMap technic described here.
PageBean.java
private String _value;
public String getValue() { return _value; }
public void setValue(String value) [ _value = value; }
public void select(String value) {
setValue(value);
}
ccSelection.xhtml
<cc:interface>
<cc:attribute method-signature="void selectAction(String)"
name="actionMethod" />
<cc:attribute name="render" />
</cc:interface>
<cc:implementation>
<t:dataTable value="#{cc.values}"
var="val"
...
>
<h:column>
<t:commandLink actionListener="#{cc.selectionValueListener}"
<f:ajax render="#{cc.attrs.render}" />
<f:attribute name="value"
value="#{val}" />
</t:commandLink>
</h:column>
</t:dataTable>
</cc:implementation>
ccSelection.java
public void selectionValueListener() {
// recover the attribute value
String value = event.getComponent().getAttributes().get("value");
// call the callback method of the page
FacesContext context = FacesContext.getCurrentInstance();
MethodExpression method = (MethodExpression) this.getAttributes().get("actionMethod");
if (method != null)
method.invoke(context.getELContext(), new Object[] {value});
}
I don't think ccDisplay is interressting.
So, if I don't put the f:ajax tag, it works.
When I put the f:ajax with the render pointing to the clientId passed in param, I get an error while loading the page.
If I change the render for #form or #all, the pageBean.select method is called, but ccDisplay is not refreshed.
I think i see a little error in page.xhtml.
See when you created the component cc:display you said:
<cc:attribute method-signature="void selectAction(String)" name="actionMethod" />
That means that a parameter is needed.
But when you call it in page.xhtml you do this:
<myComp:ccSelection actionMethod="#{pageBean.select}"...
And its backing bean method is:
public void select(String value) {
setValue(value);
}
As you see the backing bean is correct, but when you call the component in the page, there is no parameter being passed to the bean, and at the end the value is never set.
I think that might be one of the reasons.
To fix it i think you should pass the value some how:
<myComp:ccSelection actionMethod="#{pageBean.select(???Selected value
???)}"...
OK. It is solved... but I don't like it very much.
You'll think I'm a fool : I solved the problem by removing the <![CDATA surrounding my scripts !
I've already found some issue using CDATA. I don't know if this is a MyFaces bug or something I do the wrong way like putting many h:outputScript blocks with CDATA in composite components but with CDATA, I get errors or not working. Just removing it, it works !
Good Afternoon,
I have a search page that uses ajax to render a several datatables without refreshing the page.
It is mandatory for me to call a Method as a Listener for each table.
Below is the snippet for the first datatable that works fine.
To render a second datatable I need to call a method #{evalController.prepareList} as a Listener for the ajax. The problem is that <f:ajax "Listener" attribute won't take more than one method.
So the remaining way is to call <f:ajax several times, and each time with a different listener, which does not work. Is there a way to achieve this?
If not, should I create a method in the managed Bean that calls all the methods that I need and use it as the one listener?
Thanks in advance for your help.
<h:form id="searchform">
<h:panelGrid columns="3" >
<p:inputText value="#{ddnController.patientID}" id="pidinput" maxlength="7" size="7">
<f:ajax execute="#this" event="keyup" render="searchbutton ddntable" listener="#{ddnController.prepareList}"/>
</p:inputText>
<h:commandButton image="#{resource['images/search.png']}" id="searchbutton" value="#{bundle.Search}"
action="submit" actionListener="#{ddnController.prepareList}"
disabled="#{empty ddnController.patientID or ddnController.patientID.equals('0')}"/>
<p:panel><h:outputText value="Saisir 0 pour avoir tous les Patients" style="font-style: italic;"/></p:panel>
</h:panelGrid>
<p:dataTable id="ddntable" value="#{ddnController.items}" var="ddn" rendered="#{!empty ddnController.items}" paginator="true" >....
I am still not sure why the composite method do not have effect when called. Probably it is not called during before or after the right phase (I'll be profiling it later). Anyway, I found a solution with two edges (it is solving my problem but makes me sacrifice the use of ajax) :
So Instead of calling - from each managed bean - the method (prepareList()) which I use as listener:
private DataModel items = null; // Getter to retrieve items
// ......
public String prepareList() {
recreatemodel();
return "List";
}
private void recreatemodel(){
items=null;
}
(by the way, this method sets the datamodel to NULL to refresh it, and that is how my datatables get refreshed).
Inside the command button I nested property action listener:
<h:commandButton image="#{resource['images/search.png']}" id="searchbutton" value="#{bundle.Search}"
action="submit"
disabled="#{empty ddnController.patientID or ddnController.patientID.equals('0')}">
<f:PropertyActionListener target="#{ddnController.items}" value="#{null}" />
<f:PropertyActionListener target="#{evalController.items}" value="#{null}" />
<f:PropertyActionListener target="#{corController.items}" value="#{null}" />
<!--...etc -->
</h:commandButton>
I wish <f:PropertyActionListener /> could be nested inside <h:ajax/>.
If somebody has a solution that allows to use property action listener and ajax to avoid submitting the form with a button, s/he is welcome. I'll make then his/her answer as accepted.