h:inputText value is always null after AJAX event - ajax

I use ajax to enable an input text if a certain value of a selectonemenu is selected. Like this:
<a4j:outputPanel id="panelFilial">
<h:selectOneMenu id="perfil" tabindex="5"
value="#{actionCadastrarCotacaoDadosCarga.idProduto}"
label="#{msg.selecione}" style="width: 145px;"
required="false">
<f:selectItems value="#{actionCadastrarCotacaoDadosCarga.listProdutos}"></f:selectItems>
<a4j:support ajaxSingle="true" event="onchange"
action="#{actionCadastrarCotacaoDadosCarga.direcionarEnableOutros}"
onclick="javascript:Richfaces.showModalPanel('progressWaitModalPanel');
atualizarImagem();"
reRender="panelOutros" />
</h:selectOneMenu>
</a4j:outputPanel>
Here's my backing bean method:
public void direcionarEnableOutros() {
if (this.idProduto.equals(ID_PRODUTO_OUTROS)) {
this.enableOutros = false;
this.descricaoProduto = new String();
} else {
this.enableOutros = true;
}
}
When I submit my form, the value of the input text is always null. Am I missing something here?
Here's the input text:
<a4j:outputPanel id="panelOutros">
<h:inputText id="outros" tabindex="6" required="false"
maxlength="50"
value="#{actionCadastrarCotacaoDadosCarga.descricaoProduto}"
disabled="#{!actionCadastrarCotacaoDadosCarga.habilitarCampoOutros}">
</h:inputText>
</a4j:outputPanel>

Assuming you are using Seam, the problem must be the event scope. Change it to conversation scope.
Event Scope
The event (request) context. Spans a server request, from restore view
to render response.
Conversation Scope
The conversation context. Spans multiple requests from the same
browser window, demarcated by #Begin and #End methods. A conversation
context is propagated by any faces request, or by any request that
specifies a conversation id as a request parameter. The conversation
context is not available during the restore view phase.

In JSF 2.x you can make use of #ViewScoped to makee your bean alive while the user interacts with the same view e.g. ajax requests. In JSF 1.x, there's no #ViewScoped, so you had to store and remove the data from view state or even session scope manually. Still, since you're using RichFaces, you can make use of #KeepAlive annotation, which works very similar to #ViewScoped from JSF 2.
Just do this:
#KeepAlive
public class ActionCadastrarCotacaoDadosCarga {
//bean definition here...
}
And make sure the beans is configured in request scope:
<managed-bean-name>actionCadastrarCotacaoDadosCarga</managed-bean-name>
<managed-bean-class>location.of.your.bean.ActionCadastrarCotacaoDadosCarga</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<!-- ^-IMPORTANT-^ -->
</managed-bean>

Related

How to only update JSF/Primefaces component value upon Ajax sucess, but do nothing on Ajax failure

I have a JSF front end using Primefaces 5.3 which updates fields dynamically using Ajax. The problem that I am having is that sometimes my Ajax calls fail (ex: server responds with a 500), but my front end is still changing. Essentially, I'm looking to prevent the change of the input field if my ajax fails. Stated differently, I only want the input field to change upon a successful Ajax response.
I'm fairly new to JSF, so I'm not sure how to handle this. In regular HTML/JS, I would have been able to store the value onclick and in my ajax error handler restored the value, but I don't know how to do this using the PF framework.
<div class="Container25">
<p:selectOneRadio id="grid" value="#{cc.attrs.answer.singleAnswer.codeValue}" layout="grid" columns="1" >
<f:selectItems value="#{cc.attrs.menuItems}"
var="item" itemLabel="#{msg[item.code]}" itemValue="#{item.code}" itemLabelEscaped="false"/>
<p:ajax event="change" listener="#{cc.attrs.onChange}" update="#{cc.attrs.update}" disabled="#{cc.attrs.onChange == null }" global="false" />
</p:selectOneRadio>
</div>
I've tried adding the resetValues attribute to the ajax component, but that hasn't helped. Additionally, I've tried adding some custom JS in my onstart handler, but it is undefined.
I figured there must be a simple JSF/PF way of doing this, but can't seem to find it.
How can I either prevent the input value to change until the Ajax call returns successfully (ie: only change the value in the onsuccess handler) or reset my original radio button selection in the event that my Ajax call fails? What do I need to put in my onerror handler to restore the pre-ajax state?
You can use Primefaces RemoteCommand component for an easy solution, just embed it in your form:
<p:remoteCommand name="revertSomeValues"
actionListener="#{relatedBean.revertValuesToDefaults}"
update="componentId" />
And at the bean side you can manipulate the model:
#Named
#ViewScoped
public class relatedBean implements Serializable {
Integer codeValue;
//other model attributes and methods...
public void revertValuesToDefaults() {
setCodeValue(0); //supposing 0 is the default value
//handle other model attributes if needed
}
}
Now you can set the onerror callback alike -> onerror="revertSomeValues()"
You can also update the components wtih Primefaces RequestContext programatically from your bean if needed:
RequestContext context = RequestContext.getCurrentInstance();
context.update("componentId");

How to send data to a faces-flow?

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

When to use valueChangeListener or f:ajax listener?

What's the difference between the following two pieces of code - with regards to listener placement?
<h:selectOneMenu ...>
<f:selectItems ... />
<f:ajax listener="#{bean.listener}" />
</h:selectOneMenu>
and
<h:selectOneMenu ... valueChangeListener="#{bean.listener}">
<f:selectItems ... />
</h:selectOneMenu>
The valueChangeListener will only be invoked when the form is submitted and the submitted value is different from the initial value. It's thus not invoked when only the HTML DOM change event is fired. If you would like to submit the form during the HTML DOM change event, then you'd need to add another <f:ajax/> without a listener(!) to the input component. It will cause a form submit which processes only the current component (as in execute="#this").
<h:selectOneMenu value="#{bean.value}" valueChangeListener="#{bean.changeListener}">
<f:selectItems ... />
<f:ajax />
</h:selectOneMenu>
When using <f:ajax listener> instead of valueChangeListener, it would by default executed during the HTML DOM change event already. Inside UICommand components and input components representing a checkbox or radiobutton, it would be by default executed during the HTML DOM click event only.
<h:selectOneMenu value="#{bean.value}">
<f:selectItems ... />
<f:ajax listener="#{bean.ajaxListener}" />
</h:selectOneMenu>
Another major difference is that the valueChangeListener method is invoked during the end of the PROCESS_VALIDATIONS phase. At that moment, the submitted value is not been updated in the model yet. So you cannot get it by just accessing the bean property which is bound to the input component's value. You need to get it by ValueChangeEvent#getNewValue(). The old value is by the way also available by ValueChangeEvent#getOldValue().
public void changeListener(ValueChangeEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
// ...
}
The <f:ajax listener> method is invoked during INVOKE_APPLICATION phase. At that moment, the submitted value is already been updated in the model. You can just get it by directly accessing the bean property which is bound to the input component's value.
private Object value; // +getter+setter.
public void ajaxListener(AjaxBehaviorEvent event) {
System.out.println(value); // Look, (new) value is already set.
}
Also, if you would need to update another property based on the submitted value, then it would fail when you're using valueChangeListener as the updated property can be overridden by the submitted value during the subsequent UPDATE_MODEL_VALUES phase. That's exactly why you see in old JSF 1.x applications/tutorials/resources that a valueChangeListener is in such construct been used in combination with immediate="true" and FacesContext#renderResponse() to prevent that from happening. After all, using the valueChangeListener to execute business actions has actually always been a hack/workaround.
Summarized: Use the valueChangeListener only if you need to intercept on the actual value change itself. I.e. you're actually interested in both the old and the new value (e.g. to log them).
public void changeListener(ValueChangeEvent event) {
changeLogger.log(event.getOldValue(), event.getNewValue());
}
Use the <f:ajax listener> only if you need to execute a business action on the newly changed value. I.e. you're actually interested in only the new value (e.g. to populate a second dropdown).
public void ajaxListener(AjaxBehaviorEvent event) {
selectItemsOfSecondDropdown = populateItBasedOn(selectedValueOfFirstDropdown);
}
If you're actually also interested in the old value while executing a business action, then fall back to valueChangeListener, but queue it to the INVOKE_APPLICATION phase.
public void changeListener(ValueChangeEvent event) {
if (event.getPhaseId() != PhaseId.INVOKE_APPLICATION) {
event.setPhaseId(PhaseId.INVOKE_APPLICATION);
event.queue();
return;
}
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
System.out.println(newValue.equals(value)); // true
// ...
}
for the first fragment (ajax listener attribute):
The "listener" attribute of an ajax tag is a method that is called on the server side every time the ajax function happens on the client side. For instance, you could use this attribute to specify a server side function to call every time the user pressed a key
but the second fragment (valueChangeListener) :
The ValueChangeListener will only be called when the form is submitted, not when the value of the input is changed
*you might like to view this handy answer

JSF 2.0,partially rendered form field input value not updated in the bean

I have an Edit product form which is pre-populated with values from DB . User can change one or more values and post the form back. One input field called t:inputFileUpload is rendered only after an ajax request ,if the user opts to change product image.During the final postback of the edit form through a save button,the bean is not updated with the value of t:inputFileUpload field.The relevant portion of the form is below:
<h:form>
<tr>
<td>Product Image*:</td>
<td>
<h:graphicImage url="#{addItem.prodFileName}" width="100" height="100"/>
<br /><h:commandLink value="change image" >
<f:ajax render="uploadimage" execute="#this" listener="#{addItem.ChangeImage}"/>
</h:commandLink>
</td>
</tr>
<tr >
<td>
<h:panelGroup id="uploadimage">
<t:inputFileUpload rendered="#{addItem.editImgChange}" label="editImage" value="#{addItem.uploadedFile}" />
<h:messages for="prodimage"/>
<h:inputHidden id="hiddeneditimgchange" value="#{addItem.editImgChange}" />
</h:panelGroup>
</td>
</tr>
<h:commandButton value="save" action="#{addItem.EditItem}" />
</h:form>
The AddItem bean is request scoped and the relevant part of its code is :
#ManagedBean
public class AddItem extends AbstractBean{
boolean editImgChange;
private UploadedFile uploadedFile;
//..
//getters and setters
public void ChangeImage(){
this.editImgChange=true;
}
public String EditItem() {
//some logic
}
}
I have read a few similar questions some of whose answers were to make the bean viewscoped.I have tried making the bean ViewScoped ,but it breaks my initial logic of prepopulating the form values. Since i am happy with RequestScoped , I have saved the state of the editImgChange flag ,if its turning off is affecting the updation of the t:inputFileUpload . When i looked at the bean properties all is fine ,the flag is true , but the uploadedFile property is null.
As per the comments, you used <h:inputHidden value="#{addItem.editImgChange}" /> to save the state. This is not going to work. The rendered attribute is evaluated during apply request values phase, while that hidden value is made available during update model values phase which is thus too late.
Since you're already using Tomahawk, use <t:saveState value="#{addItem.editImgChange}" /> instead. Or, just fix the problem which you encountered when making the bean view scoped. I don't forsee why that would be a problem. Perhaps you're using #PostConstruct and expecting that it's invoked on every request. You should then use <f:event type="preRenderView"> instead.

How to call several methods with JSF <f:ajax listener?

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.

Resources