f:ajax listener method argument - jsf

TODO: Get selected row in h:datatable.
Code Snippet using HtmlDataTable binding:
<h:dataTable value="#{bean.licenses}" var="license" rendered="#{!empty bean.licenses}" binding="#{bean.dataTable}">
<h:column>
<h:selectOneRadio onclick="uncheckOthers(this);" >
<f:selectItem itemValue="null" />
<f:ajax listener="#{bean.updateSelected}" render="licenseGenerator:submitButtons">
<f:param name="license" value="#{license}" />
</f:ajax>
</h:selectOneRadio>
</h:column>
</h:dataTable>
So the above mentioned is one way to do it, however since I am already using EL 2.2, I was trying to do something like the accepted answer. and update f:ajax to
<f:ajax listener="#{bean.updateSelected(license)}" render="licenseGenerator:submitButtons">
When I update the code with the above code, the listener is not getting invoked so I checked the documentation which says:
javax.el.MethodExpression (signature must match public void
processAjaxBehavior(javax.faces.event.AjaxBehaviorEvent event) throws
javax.faces.event.AbortProcessingException)
So, basically with the above signature I can't use something like
public void listener(License license){
//...
}
However, since it was the accepted answer, I am sure I am missing something here. Thanks for the help!
JSF Version: Mojarra JSF Implementation 2.2.12
Server: Apache Tomcat 8.0.24

Related

Primefaces - Cant find method when passing parameter to action

I am trying to pass parameters to my backing bean using action (testPlan and rowIndex). But when I run the code it says it can't find the method.
<p:commandLink update=":scriptGroupPopupID" ajax="true"
action="#{workloadScripts.initCurrentGroup(testPlan, rowIndex)}"
immediate="true"
oncomplete="PF('scriptGroupPopup').show();">
<f:param name="insertIndex" value="#{rowIndex}" />
</p:commandLink>
public void initCurrentGroup(String testPlan, String rowIndex) {
...
}
However, if I remove the parameters from initCurrentGroup method only, it does work. What is going on here?
The type of the rowIndexVar variable is an int. You must use a matching method signature. Assuming testPlan is indeed a String, you should use:
public void initCurrentGroup(String testPlan, int rowIndex) {
...
}
Which you can use like:
<p:commandLink update=":scriptGroupPopupID"
action="#{workloadScripts.initCurrentGroup(testPlan, rowIndex)}"
process="#this"
oncomplete="PF('scriptGroupPopup').show();" />
Please note that I've removed ajax="true" (which is default), and replaced immediate="true" with process="#this".
See also:
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes

Using a4j:support with jsf 1.2

I need to make some save action on h:selectonemenu. When it's value change then it should save this value, but without page refresh (so without submit).
Unfortunatelly I must work with jsf 1.2. After some research I've found that it can be done with a4j:support, however I have no idea how to include it into my project. Do I need to download some old richfaces libraries ? (as i know richfaces 4 doesnt support jsp syntax). Or does exists some other way to achieve this goal ??
1. You could use Richfaces 3.3.4.Final (downaload here).
This is way you should include, register and use libraries in a project. Notice:
A JSF application with RichFaces assumes that the following JARs are available in the project: commons-beanutils-1.7.0.jar, commons-collections-3.2.jar, commons-digester-1.8.jar, commons-logging-1.0.4.jar, jhighlight-1.0.jar.
Example (from developer guide) for your case:
<h:form id="planetsForm">
<h:outputLabel value="Select the planet:" for="planets" />
<h:selectOneMenu id="planets" value="#{planetsMoons.currentPlanet}" valueChangeListener="#{planetsMoons.planetChanged}">
<f:selectItems value="#{planetsMoons.planetsList}" />
<a4j:support event="onchange" reRender="moons" />
</h:selectOneMenu>
<h:dataTable id="moons" value="#{planetsMoons.moonsList}" var="item">
<h:column>
<h:outputText value="#{item}"/>
</h:column>
</h:dataTable>
2. Example of other solution:
You could use jQuery.ajax() with custom servlet.
JS:
$.ajax({
type: 'GET',
url: '/app/customservlet.jsf?value=' + selectOneValue; //selected value
});
Servlet:
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) {
String selectOneValue = req.getParameter("value");
//do something
}

how to rerender a4j:commandLink after the action has been completed

i have a very simple code here:
<a4j:commandLink action="#{ticketAboxEventHelper.removeAboxTicket(ticketAbox)}"
onclick="if(!confirm('Are you sure ... ?')) return false;"
reRender="aboxlistpanel">
<h:graphicImage alt="Delete" url="../../img/dialog-error-5.png" title="Delete" />
<a4j:support event="oncomplete"
action="#{editTicketNewAction.testRerender()}"
reRender="aboxlistpanel"
/>
</a4j:commandLink>
When the link clicked the system must
ask if the user is confirmed
do the action
rerender the aboxlistpanel
Now my problem is the rerendering is hapenning before the action is getting finished. any idea how it can be done in the right way?
Your action methods is not valid for JSF 1.2 and you don't need the <a4j:support>. Since you want to pass a parameter, you should use <f:attribute /> and actionListener :
<a4j:commandLink actionListener="#{ticketAboxEventHelper.removeAboxTicket}" onclick="if(!confirm('Are you sure ... ?')) return false;" reRender="aboxlistpanel">
<h:graphicImage alt="Delete" url="../../img/dialog-error-5.png" title="Delete" />
<f:attribute name="ticket" value="#{ticketAbox}" />
</a4j:commandLink>
Your bean method will look like this :
public void removeAboxTicket(ActionEvent event)
{
TicketAbox ticket = (TicketAbox)event.getComponent().getAttributes().get("ticket");
// Your business logic
}
More info :
How to pass parameters in method expression JSF 2.0
Solved. I wrapped the offending JSF code in a and everything began working as expected. related to answer <a4j:commandLink> Not Rerendering. i solved it first and then found out someone else solved it in the same way. hmmm....

How to send the currently iterated item to h:selectBooleanCheckbox with f:ajax event=change

I've the below form:
<h:form>
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<h:selectBooleanCheckbox value="#{item.enabled}" valueChangeListener="#{bean.onchangeEnabled}">
<f:ajax event="change" />
</h:selectBooleanCheckbox>
</h:column>
<h:column>#{item.name}</h:column>
</h:dataTable>
</h:form>
I would like to get #{item} or at least #{item.name} in the value change listener method:
public void onchangeEnabled(ValueChangeEvent e) {
// I would like to get #{item.name} here too.
}
How can I achieve this?
First of all, the valueChangeListener is the wrong tool for the job. Use <f:ajax listener>. Second, event="change" is the wrong choice in case of checkboxes/radiobuttons because their physical value actually never changes. You should use event="click", but this is the default already, so you can just omit it.
All in all, the proper initial code should look like this:
<h:selectBooleanCheckbox value="#{item.enabled}">
<f:ajax listener="#{bean.onchangeEnabled}" />
</h:selectBooleanCheckbox>
with
public void onchangeEnabled(AjaxBehaviorEvent event) { // Note: event argument is optional.
// ...
}
Once fixed it like that, then you can easily make use of EL 2.2 capability to pass method arguments:
<h:selectBooleanCheckbox value="#{item.enabled}">
<f:ajax listener="#{bean.onchangeEnabled(item)}" />
</h:selectBooleanCheckbox>
with
public void onchangeEnabled(Item item) {
// ...
}
See also:
When to use valueChangeListener or f:ajax listener?
What values can I pass to the event attribute of the f:ajax tag?
How can I pass selected row to commandLink inside dataTable?
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
For selectBooleanCheckbox it only reacts on the event click and the form should be posted.
so add this to the checkbox
valueChangeListener="#{mybean.myfunction}" onchange="submit();"
it should get fired !

JSF dataTable with selectOneListbox

I have a dataTable that lists some objects and I want to set a property for those objects using a selectOneListbox. This is my dataTable
<h:dataTable value="#{someHandler.entities}"
binding="#{someHandler.dataTable}" var="entitiy">
<h:column>
<f:facet name="header">
<t:outputText value="Level" />
</f:facet>
<h:selectOneListbox id="level" value="#{entitiy.level}" size="1"
valueChangeListener="#{someHandler.changeLevel}"
onchange="submit()">
<f:selectItem itemValue="-" itemLabel="-" />
<f:selectItem itemValue="ALL" itemLabel="ALL" />
(and so on)
</h:selectOneListbox>
</h:column>
<h:column>
<f:facet name="header">
<t:outputText value="Name" />
</f:facet>
<h:outputText value="#{entitiy.name}" />
</h:column>
</h:dataTable>
The valueChangeListener looks like this:
public void changeLevel(ValueChangeEvent event) {
String newLevel = (String) event.getNewValue();
Logger logger = (Logger) dataTable.getRowData();
logger.setLevel(Level.toLevel(newLevel));
}
(dataTable is an HtmlDataTable object.)
However, the event object is always the same - no matter which row the selectOneListbox was in. (It seems always the logger in the first row). The Logger object I get is also not the one I want.
Any ideas? Thank you!
And anothers questions? Is the entitiy.setLevel() method called even though I have a valueChangeListener? I use entitiy.level because I want to show the chosen level as a default for those entity.
Thank you!
There are two potential problems here:
First, the onchange="submit()" submits the entire form. The valueChangeListener will be invoked on all input elements of which the submitted value differs from the initial value.
You need to preset the value behind #{entitiy.level} with the same value as the default menu option. E.g. in the constructor.
public Entity() {
level = "-";
}
Or, better, make the default value null.
<f:selectItem itemValue="#{null}" itemLabel="-" />
so that the valueChangeListener won't be invoked when the particular menu is not changed.
Or, when you are already on JSF 2.x (please always mention exact JSF impl/version in your JSF questions), you can use <f:ajax> tag for this without the need for a valueChangeListener with a hacky onchange="submit()".
Second, you need to ensure that the datatable value #{someHandler.entities} returns exactly the same list during the submit as it was during the initial request. So, do the data loading in the bean (post)constructor. In JSF 2.x you'd like to put the bean in the view scope as well.
Unrelated to the concrete problem, you can also just use <h:selectOneMenu> instead of a <h:selectOneListbox size="1">.

Resources