Passing parameters to a4j:ajax method - jsf

I am trying to use <a4j:ajax> to feed a method with a value just entered on the form;
<h:selectOneMenu id="aa" value="#{colorClass.color}">
<f:selectItems value="#{myChoices.colorOptions}"/>
<a4j:ajax event="change" render="colorCode"
execute="#{myChoices.getColorCode(colorClass,colorClass.color)}"/>
</selectOneMenu>
Color on the form is selected correctly;
my problem is that when I pass colorClass.color as part of the execute, it is blank;
if I replace colorClass.color with a literal
<a4j:ajax event="change" render="colorCode"
execute="#{myChoices.getColorCode(colorClass,'green')}"/>
the method is called, finds the colorCode and repaints the form
How can I "grab" the value just entered so that I can pass it as a parameter to the method?

You need listener attribute instead of execute attribute. The execute attribute should point to a collection of client IDs which are to be submitted (which defaults to #this in <f:ajax> and #form in <a4j:ajax>). However in your particular case it returns void and keeps the execute empty. The listener attribute is supposed to point to a bean action listener method. Fix it accordingly:
<a4j:ajax event="change" render="colorCode"
listener="#{myChoices.getColorCode(colorClass,colorClass.color)}"/>
Note that the colorClass argument seems superfluous here, or at least the colorClass.color as you could also just do colorClass.getColor() inside the getColorCode() method. Just passing one of them ought to be sufficient. Passing colorClass.color would be preferable so that your myChoices bean is not tight coupled with the colorCode bean.
<a4j:ajax event="change" render="colorCode"
listener="#{myChoices.getColorCode(colorClass.color)}"/>

Related

JSF h:selectOneMenu wont call relevant setter method

Hi I've got a question
<h:selectOneMenu id="cmbFileStatus1" disabled="#{!schedulerController.oldFile}"
value="#{schedulerController.test}">
<f:selectItem itemValue="#{null}" itemLabel="--Show All--" noSelectionOption="true"/>
<f:selectItems value="#{schedulerController.statusList}"/>
<f:ajax execute="#this" render="dataTable"/>
</h:selectOneMenu>
The above code the ajax executes(I checked through firebug). But the thing is the selected value wont be set to h:selectOneMenu value parameter.
There is a h:form tag that is wrapping this element, plus there are two other elements similarly using ajax as shown here. But they are positioned before this element in the DOM, they call the relevant setter methods and the updates the bean variables.
But this element it doesn't set necessary selected value.
Also another detail, the list that is populated for selection, it is a list created from enum values.
One instance I moved the problematic code to the top of the DOM (before the other two elements that ajax is applied) and then it hit the setter method when ran in debug mode.
I cannot understand whats wrong, it doesn't show any javascript errors and such. The JSF version is 2.0, this is an old project.
Any ideas guys?

What different between p:param and custom attribute

I suspect about 2 way of passing value through attribute.
First: f:param
<p:inputText value="#{inputTextView.inputVal}">
<f:param name="fieldA" value="inputA" />
<p:ajax process="#form" update="#form"></p:ajax>
</p:inputText>
Second: custom field
<p:inputText value="#{inputTextView.inputVal}"
fieldB="inputB">
<p:ajax process="#form" update="#form"></p:ajax>
</p:inputText>
The first way, I can get value of attribute by using
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("fieldA");
While the second way use
UIComponent.getCurrentComponent(FacesContext.getCurrentInstance()).getAttributes().get("fieldB");
Does anyone know what different between first and second?
What situation which appropriate for use the first approach?
First of all, if you want to set a custom attribute, you cannot just add a random new attribute to a tag because JSF ignores unsupported tag attributes. BalusC gives some options on how to work around this in this answer.
f:param should be used if you want to add values to the query string or request parameters. It should be used with command components (e.g. h:commandButton, h:commandLink or h:outputLink).
f:attribute on the other hand, adds entries to the attribute Map of a component.

Post value using h:inputtext and a4j:support onkeyup

I was originally posting a value in the h:inputText field with an a4j:commandButton but I had to change the commandButton to s:link because the commandButton is also triggering a pdf document to be exported, and I believe that with an ajax call, the doc is rendered on the browser instead.
So now I am trying to post the value using h:inputText and a4j:support
<h:inputText id="numberOfPatients"
value="#{printLabelsReqFormsAction.numberOfPatients}">
<a4j:support event="onkeyup"
action="#{printLabelsReqFormsAction.setNumberOfPatients(numberOfPatients)}"/>
</h:inputText>
(sorry for the weird formatting..)
My setNumberOfPatients(x) is getting called but I don't think I am passing the value correctly. How should I pass the value of the h:inputText field?
You don't need to explicitly set the value of numberOfPatients while executing ajax support. a4j:support tag processes its parent component during its execution, meaning the value for numberOfPatients will be set for each onkeyup event, even you don't invoke an action event. You can see it better at Richfaces' site:
RichFaces uses form based approach for Ajax request sending. This means each time, when you click an Ajax button or produces an asynchronous request, the data from the closest JSF form is submitted with the XMLHTTPRequest object. The form data contains the values from the form input element and auxiliary information such as state saving data.
When "ajaxSingle" attribute value is "true" , it orders to include only a value of the current component (along with or <a4j:actionparam> values if any) to the request map. In case of <a4j:support> , it is a value of the parent component. An example is placed below:
<h:form>
<h:inputText value="#{person.name}">
<a4j:support event="onkeyup" reRender="test" ajaxSingle="true"/>
</h:inputText>
<h:inputText value="#{person.middleName}"/>
</form>
In other words, for your case this should work:
<h:inputText id="numberOfPatients"
value="#{printLabelsReqFormsAction.numberOfPatients}">
<a4j:support event="onkeyup" ajaxSingle="true"/>
</h:inputText>
Specify an action method only if you want to add extra logic when the event happens.

Pass an input value directly as action method argument

Is there a way to do pass an input value as a action's parameter without using managed properties?
i.e.
<h:form>
<h:inputText id="input" />
<h:commandButton action="#{someBean.doSome(input)}" />
</h:form>
Yes, it's during the form submit already there in the JSF component state. Just bind the input component to the view by binding attribute, which will reference an UIInput instance, which in turn has a getValue() method for the very purpose of retrieving the input value (so that you can pass it as action method argument):
<h:form>
<h:inputText ... binding="#{input}" />
<h:commandButton ... action="#{someBean.doSome(input.value)}" />
</h:form>
The properness of this approach is however highly questionable and depends on concrete functional requirements. This approach is namely basically tight-coupling the view with the model and therefore considered a bad practice.
See also:
How to send form input values and invoke a method in JSF bean
How does the 'binding' attribute work in JSF? When and how should it be used?

JSF selectOneMenu is refreshing and going back to its previous state rather than showing the new value

I have a datatable where a lot of selectOneMenu items are available , for example, for 10 items each having one selectOneMenu combo. now if i click on any of the combos, they are supposed to save the value in the database and they do it. but after saving the changed value the selectOneMenu is returning back to its previous state. I want the selectOneMenu to keep its current state. also, the method is being invoked for every single combo in the datatable. i really wonder why!! i have been banging my head for the last 2 weeks. any help would be really appreciated. thanks in advance.
this is my first post here. this is my jsf datatable:
<h:dataTable value="#{careNeedBean.controlledCareNeedsList}" var="careNeed"
id="careneed_table" binding="#{careNeedBean.dataTable}">
<h:column>
<f:facet name="header">
<h:outputText value="NeedsLevel"/>
</f:facet>
<h:selectOneMenu id="needs_level_combo" style="width:200px;font-size:9px;"
onchange="submit()"
valueChangeListener="#{careNeedBean.saveTaskAsessment}"
binding="#{careNeedBean.selectOneMenu}">
<f:selectItem itemValue="not_assessed" itemLabel="----Not assessed----"/>
<f:selectItems value="#{careNeed.humanReadableNeedsList}" />
</h:selectOneMenu>
</h:column>
This is my bean code:
public String saveTaskAsessment(ValueChangeEvent event) {
//does some things
return "Success";
}
The valueChangeListener doesn't run on the recently changed component only. In fact, you're using JavaScript submit() function to submit the entire form. The valueChangeListener will always be executed whenever the new selected value differs from the old value as is been declared in the value attribute.
You don't have declared a value attribute, so its default value is effectively null. If the default selected item of the list is not null, then the valueChangeListener will be invoked.
To fix this, you need to assign a value attribute to the component
<h:selectOneMenu value="#{careNeed.needsLevel}">
and you need to prefill it with the same value as the default value of the dropdown list.
this.needsLevel = "not_assessed";
Alternatively, you can also make the default value null.
<f:selectItem itemValue="${null}" itemLabel="----Not assessed----"/>
Unrelated to the problem, since you're already on JSF 2.0, I'd suggest to use <f:ajax> to submit only the recently changed dropdown by ajaxical powers instead of using onchange="submit()" to submit the entire form. That's after all better for user experience.
<h:selectOneMenu>
<f:ajax />
</h:selectOneMenu>
Also, the valueChangeListener method doesn't need to return anything. It will be ignored anyway. Just declare it void.
You can use AjaxSingle="true" and onsubmit="form.refresh();" on your ajax request.
So that it will process only the current component.
form.refresh(); will remove the old cache value.
You will get the refreshed bean value.

Resources