JSF custom component not updating value for AJAX - 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.

Related

Form values not submitted, reset on 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.

Primefaces automatically pass parameter from selectOneMenu without using command button

I would like to call an action from a backing bean immediately after a value in a PF selectOneMenu is selected without using any button or link. I already looked at this question:
When to use valueChangeListener or f:ajax listener?
While very useful, I am not able to apply the recommended business logic that would allow the action to be called dynamically based on ONLY the selected value from the menu. I know how to use ajax to render changed values between two menus (where the value of one menu is changed). The options discussed on the above questions do not seem to work in my case which leads me to look deeper into the EL and backing bean methods to understand these concepts better.
I tried two ways to allow dynamic processing of my menu paramteres. The first was to use the valueChangeListener ayttribute in the EL:
<p:selectOneMenu id="Ctl" value="#{actionBean.department}"
valueChangeListener="#{actionBean.ShowListDeptAct(event)}" onchange="submit()">
<f:selectItem itemLabel="Dept A" itemValue="Dept A"/>
<f:selectItem itemLabel="Dept B" itemValue="Debt B"/>
<f:selectItem itemLabel="Dept C" itemValue="Dept C"/>
</p:selectOneMenu>
The bean method:
public void ShowListDeptAct(ValueChangeEvent event) {
department = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("department");
listDeptActions();
}
public String listDeptActions() {
//department = getDepartment();
deptActions = facade.findByDept(department);
return "DeptAction";
This only results in refreshing the page and the bean method does not even to be functioning.
The second way was to use the p ajax tag:
<p:selectOneMenu id="Ctl" value="#{actionBean.department}">
<f:selectItem itemLabel="Dept A" itemValue="Dept A"/>
<f:selectItem itemLabel="Dept B" itemValue="Debt B"/>
<f:selectItem itemLabel="Dept C" itemValue="Dept C"/>
<p:ajax listener="#{actionBean.ShowListDeptAct}" oncomplete="submit()"/>
</p:selectOneMenu>
bean method:
public void ShowListDeptAct(AjaxBehaviorEvent event) {
department = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("department");
listDeptActions();
}
public String listDeptActions() {
//department = getDepartment();
deptActions = facade.findByDept(department);
return "DeptAction";
}
This resulted in exactly the same behavior which makes me think my problem might be a mistake in how I"m writing the listener.
The EL is supposed to pass the name of the selected department to the following backing bean methods which will display a dataTable of the data for the selected department. The backing bean methods:
After reading the PF User Guide and some questions here, I'm neither sure about how to pass the correct EL nor the right backing bean methods to achieve this. Would appreciate some guidance. Thank you!
When you work with Ajax, it is very important to always keep in mind which part of the view needs to be submitted to the server and which part needs to be updated as the response. This is the number one error source when dealing with Ajax-Requests.
For the <p:ajax>-Tag, this is specified with the attributes process and update, in pure JSF <f:ajax> the attributes execute and render are used.
This is very helpful to read to understand how these work:
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
In your first attempt you try to get the parameters from the request parameter map, which is not a good idea, because the key of each request parameter will be the id of the component that is sent. You would have to know the components' id to get the value. It is not recommended to work with component ids on the server side, if possible, as they may change when enclosing naming containers change and are therefore unreliable. Also this heavily interferes with separation of view and program logic.
The best attempt is to bind the values of components to variables on server side beans, as you already did, an work with them.
In your second attempt, the default value of process in the <p:ajax>-Tag is null, so there are no values of components sent to the server. If you write
and bind the value of the <p:selectOneMenu> to a variable on the server, you can use the value of the department in the doAction()-Method.

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