Form values not submitted, reset on ajax - ajax

In my current project I have a construct, where you have an entity where you can change the values through a approval workflow.
If you want to save a new version of an entity, you click on a button and a dialog pops up. There you can set the one to approve your change and an additional, optional comment.
My problem is, that the values from this dialog are not submitted.
The dialog is included in my main template, but outside of the main form. The dialog is appended to the Body, like this:
<p:dialog id="idEntityCommentDialog"
header="#{msgs['label.approval.dialogHeader.'.concat(bean.targetStatus)]}"
width="350" widgetVar="entityCommentDlg" modal="true"
maximizable="false" resizable="false" appendTo="#(Body)">
Both fields set their value to an object inside the sessionScoped backing bean:
<p:selectOneMenu id="selUsers"
value="#{bean.state.releasedBy}" style="width: 100%">
<f:selectItems value="#{bean.fetchUserList()}" var="user"
itemValue="#{user.id}"
itemLabel="#{user.name}" />
</p:selectOneMenu>
<p:inputTextarea id="changeComment"
value="#{bean.state.newComment.eventDescription}"
style="width: 98%; height: 100px">
<f:converter converterId="xssConverter" />
</p:inputTextarea>
Before, I had standard jsf controls, h:sekectOneMenu and h:inputTextArea. I have switched to the respective primefaces controls, and now at least the value from the selectOneMenu is submitted, but still, the value from the inputTextarea is not submitted. I have set breakpoints in the used converter, and I receive an empty string in my converter, which works in different other places where I use it.
I tried various combinations of update parameters and I also tried to set the value in an ajax request via
<p:ajax event="change" update="#this">
When I use the p:ajax tag, I can see, that when I change the value, after the ajax request, the value is immediately reset to the original value before the change. This applies for both fields (when using the standard controls) Like I said, I fixed it with the primefaces control (I don't understand why, but it seems to work) but it doesn't work for the inputTextArea.
My button is inserted with a toolbar facet from primefaces.
<p:commandButton actionListener="#{bean.saveEntity}"
styleClass="toolbarButton" update="dialogForm2 :blocker:contentWrapper"
onstart="PF('waitDialog').show();"
oncomplete="PF('waitdialog').hide();PF('entityCommentDlg').hide();"
value="#{msgs['label.approval.button.'.concat(bean.targetStatus)]}">
</p:commandButton>
The form is defined inside the dialog with just an id:
<h:form id="dialogForm2">
I am mostly confused, that if I use the p:ajax control, that my value is reset immediately, so there must be something very wrong here.
I also checked that I have no failed validations that I maybe don't see for some reason (via a phaseListener) but that's not the case, no facesMessages occur.
Please respect that I can't show you complete chunks of code from the project, my customer wouldn't want that, but if you need further information about other code or architecture, I will try to provide it. I also changed some ids and names, but I made sure that they are correct and referenced properly in the original code.
Do you have any idea what could be the reason for this kind of behaviour?
I know there are various articles about form values not submitted, I have seen them and tried the solution, but nothing seems to work for me here. A colleague of mine also has no idea why it shouldn't work. I use nearly the same construct (with a different backing bean and objects) in another part of the application, there, everything works fine, with the standard jsf controls.

Ok, I finally found the problem. The solution was to remove appendTo="#(Body)"
I had very strange behaviour before I found the solution.
You see, in the onStart and onComplete events of the submit button, I display a loading overlay. The bug occured as I fixed this loadingOverlay. Before I had a copy&paste error, where I referenced the wrong loading overlay, which was not present in the current page. But the bug only occured when I used the correct overlay or I even deleted the reference to this overlay completely. When I put in the wrong id of the overlay again, it worked...
Now, when I removed the appendTo attribute, everything seems to work fine, even the correct loading overlay. I don't even know anymore why I used the appendTo attribute. I assume the dialog was in another place before and I had to use it, but meanwhile the dialog is placed directly in the body of the document, outside of any layout or form, so I understand that I don't need it.
Does someone has a more educated idea why this error happened like it did? I understand that appendTo can have side effects when you don't need to use it, but the general behaviour I could observe here is beyond any reason to me.

Related

Page not updating after ajax call

I have a custom component (that is, an xhtml file with ui:composition inside) where I have a file upload field. When a file is selected it is uploaded via AJAX like this
<uc:fileUpload
id="#{id}fileUploadComponent"
idSuffix="#{id}fileUploadSuffix"
value="#{fileUpload.docsFilePart}"
accept="#{fieldWrapper.acceptedFileTypes}"
widgetVar="#{id}documentUploadWidget"
nullAllowed="#{!((fieldDef.mandatory and
fieldWrapper.getCurrentFileCount() lt 1) and isSaving)}"
maxSize="#{customField.maxFileSize}" >
<f:ajax listener="#{fileUpload.uploadNewFile(fieldWrapper)}" render="#{localId}fileUploadMain messages"/>
</uc:fileUpload>
Below this upload there's a <div> with the same id as specified in the render attribute of the ajax call, where links for downloading the files are shown. What happens is weird - after a file is selected, it is uploaded, the <div> is updated correctly with a link to the newly uploaded file. However when I click "Cancel" or "Save" on the page, their according actions are called, a correct response is returned to the browser (with status 200) but the browser seems to ignore it - the page is not visually updated or anything...
The custom component is quite big piece of code with not-so-easy-to-rewrite logic so replacing it at this point will be... hard...
One thing to not might be that uploading the file happens in a separate controller, while the main page controller is another one. This is because the separate controller is supposed to handle uploads from the custom component.
I can't really understand what exactly happens, even less why, and I'll appreciate any ideas!
For what it's worth, I am using Mojarra on Wildfly 11 (the one provided by the AS)
As it turns out, the reason is that file uploading via JSF AJAX causes the creation of an iframe called "JSFFrameId" and that frame being set as the target of the nesting form. After the AJAX request completes the target is not removed/cleared thus causing responses to go into that iframe and breaking the view.
At this point I am not sure what causes this, but a workaround for me is to have onevent in the <f:ajax> definition, that clears the form target, like this:
<f:ajax
listener="#{fileUpload.uploadNewFile(fieldWrapper)}"
onevent="function(e){if (e.status == 'complete') { $(e.source).parents('form').attr('target','');}"
render="#{localId}fileUploadMain messages">
I will check what other states may need handling but basically this solves the problem. It may be useful if someone shares their suspicions on what may have caused JSF to leave behind this iframe and not reset the target of the form.

JSF custom component not updating value for AJAX

I'm trying to figure out how to extend BalusC's inputDate example here. I'd like the component to update the value on each change of one of the dropdowns and fire an event, something like this:
<balusc:inputDate value="#{myBean.date}">
<p:ajax event="valueChange" update="someOtherComponent"/>
</balusc:inputDate>
<h:outputText id="someOtherComponent" value="#{myBean.formattedDate}"/>
The someOtherComponent depends on values that get updated when #{myBean.date} gets updated. (See note at the end on update= complications.)
I believe this would require modifying the inputDate component to first of all announce in the <cc:interface> section that it has a valueChange behavior, something like this:
<cc:clientBehavior name="valueChange" targets="day month year" event="change"/>
This gets the event to fire, but it is not enough to get the value updated, and I am at a loss as to what to change to make it both change the value and fire the event. So the question is:
How do you add the ability for a composite component to live-update its value so they are available for AJAX events?
The environment I'm running with is Windows 7, Java 1.7.0_80, Tomcat 7.0.68 with its version of EL, JSF Mojarra 2.2.8-14, jstl 1.2, Eclipse Mars.2 (4.5.2).
P.S. I've noticed that when adding f:ajax or p:ajax elements with render= or update=, it's difficult to get the outside components to refresh. Even the ugly workaround of :#{component.namingContainer.parent.namingContainer.clientId}:someOtherComponent doesn't work, but the very messy :#{component.namingContainer.clientId.substring(0, component.namingContainer.clientId.lastIndexOf(':'))}:someOtherComponent does.

Conditional update in Primefaces/jsf

First of all, so that there are no misunderstandings, while this is the same question as PrimeFaces: conditional update on validation I am asking it again, because the answer to that question is not acceptable to me, because while it may have given the original poster a workaround for what they were asking, it doesn't really answer the question, and this workaround doesn't work for me.
So, here's my question: how do I conditionally update a primefaces component based on the results of the submition?
I have a component that must not, under any circumstances be updated UNLESS the validation is successful and backend code was executed successfully. (i.e. if the validation succeeds but there was an SQL exception on the back end, the component still shouldn't be updated).
Why can't I always update it? If the logic doesn't succeed it'll be updated to the same thing it was before the submit button was clicked. Because I can't. It's the captcha component. If you update it via ajax, it disappears, end of story. There was a ticket opened at Primefaces and they closed it as won't fix, because flash compoents aren't supposed to be updated w/ ajax.
So when I submit the form, unless the logic succeeds I need to leave the captcha alone. IF the logic succeeds, I need to make sure the captcha disappears off screen. What's the easiest, cleanest way to do it?
Excuse me if this is a n00b question. I'm really new to Primefaces and JSF.
RequestContext.getCurrentInstance().update("clientId")
Helps for conditional updates.
For recaptcha try
RequestContext.getCurrentInstance().execute("Recaptcha.destroy()");
You can use a combination of JavaScript and RemoteCommand:
<p:commandLink action="#{bean.doIt()}" process="#form" update="#none" oncomplete="if(!args.validationFailed){updateMyImportantUI();}" />
<p:remoteCommand name="updateMyImportantUI" process="#this" update=":myImportantID" />
You can use a variable at the backing bean and use it on the xhtml part.
Like this:
update="#{backingMB.updateString}"
So, after the condition you can put the value for updateString, but when you define it on the backingMB, you need to put it as:
String updateString=""; // this will be id of the component to be updated
This way you won't get a NullPointerException.

Primefaces Autocomplete returning list is based on the values of other fields. How do I do?

Pictures speak better than words...
I want to return the street address but for that I have to pass city and state. I've tried many ways and I could not, because I'm not understanding but I think when I make an ajax autocomplete and set the values ​of city and state, the values don't are going through to the managedbeans. They pass only when I advance in wizard, perhaps because the autocomplete process and just update itself (even me trying to update the other fields through other ajax requests within autocomplete tags).
The following code:
<p:autoComplete global="true" id="autoCompleteEnderecoCidadesLogradouro"
completeMethod="#{cidadeMB.autoCompletaEnderecoPojo}"
value="#{cidadeMB.enderecoTemp}" var="e" itemValue="#{e}"
itemLabel="#{cidadeMB.cidade.endereco.logradouro}" converter="enderecoConverter"
forceSelection="true" minQueryLength="5" maxResults="15" queryDelay="800"
styleClass="textoLogradouro">
<p:ajax process=":tabViewSistema:tabViewCadastro:formAddCidades:testeCidadeInput"
update=":tabViewSistema:tabViewCadastro:formAddCidades:testeCidadeInput"/>
<p:column>#{e.logradouro}</p:column>
<p:column>#{e.cep}</p:column>
<p:column>#{e.uf}</p:column>
<p:ajax event="itemSelect" listener="#{cidadeMB.handleSelecaoDeEndereco}"
update=":tabViewSistema:tabViewCadastro:formAddCidades:panelAddCidadesT3"/>
</p:autoComplete>
Can anyone give me a hint how to do it?
Other people had the same problem, and PrimeFaces addressed this:
Issue 3593: Add process option to autocomplete
Summary: Add process option to autocomplete
Labels: TargetVersion-3.2
[...]
We'll add process option which you can use to add other component
on page to decide what to process during search request.
[...]
Done, you now can do process="otherComponents" while entering data.
So you can now add attribute process="otherComponent1 otherComponent2" to the <p:autocomplete>. JSF should then set the values from those componentes in the backing bean on every autocomplete callback, just like during a regular submit, and your autocomplete callback can refer to the values.

Basic ajax functionality in RichFaces

I have a lot of trouble finding proper, full examples on how to send values using Ajax when some event happens on the client side.
A basic example could be a list of cars. Each car has a name and an id. When a car is clicked, the id of the car is sent to the server.
What is the idiom for this in RichFaces using a4j? Or should I try this with plain jsf2?
I find easily parts of what I need but always there's some missing part that glues the thing together. Of course, there's always workarounds but I need a solid, robust way.
Just bind the value of the component,
value="#{bean.selectedCar}"
and had to your component an a4j:support event :
E.g. for comboBox
<a4j:support event="onchange" action="#{bean.method}" />
E.g. for dataTable
<a4j:support event="onselectionchange" action="#{bean.method}" />
In the method on the bean public void method() you can read data of bean.selectedCar.
I hope this help you.
This may help: http://mkblog.exadel.com/2009/02/how-to-delete-a-row-in-jsf/

Resources