JSF resets fields when doing an ajax update
ajax, jsf-2
Solution
The `<f:ajax>` processes by default only the current component as in `execute="@this"`. So the submitted values of all other input components won't be processed and thus not be updated into the model. However, you're by `render="@form"` forcing the entire HTML output of the form to be refreshed with current (non-updated!) model values of all other input components.
Assuming that your intent is to not unnecessarily convert/validate/update all other input components, you'd better make the `render` attribute more specific. Update only the content which really needs to be updated and not the entire form.
<p:selectBooleanCheckbox value="#{addressBean.copyBillingAddress}" id="duplicateBillingDetails">
<f:ajax render="copyBillingAddress" />
</p:selectBooleanCheckbox>
<h:panelGroup id="copyBillingAddress">
<h:panelGrid rendered="#{not addressBean.copyBillingAddress}" columns="3">
<p:inputText value="#{addressBean.deliveryAddress.firstName}"/>
</h:panelGrid>
</h:panelGroup>
Or, if you really need the `render="@form"`, then you need to add a `execute="@form"` in order to tell `<f:ajax>` to process all other input components as well.
<f:ajax execute="@form" render="@form" />
Note that this may unnecessarily trigger conversion/validation on those input components.
See also:
- Why do I need to nest a component with rendered="#{some}" in another component when I want to ajax-update it?
Problem
I have a problem on my JSF page where I type a name into the first billing first name field. If I click on copy billing address checkbox; this stops rendering the delivery address panel and hides it via ajax, the value I just typed into the first field gets reset to its previous state. JSF Page ``` <h:form> <p:inputText value="#{addressBean.billingAddress.firstName}" required="true"/ > <p:selectBooleanCheckbox value="#{addressBean.copyBillingAddress}" id="duplicateBillingDetails"> <f:ajax render="@form" /> </p:selectBooleanCheckbox> <h:panelGrid rendered="#{not addressBean.copyBillingAddress}" columns="3"> <p:inputText value="#{addressBean.deliveryAddress.firstName}"/> </h:panelGrid> <p:commandButton value="Checkout" action="#{addressBean.saveAddress}"/> </h:form> ``` Backing Bean ``` @Component @Scope("view") public class AddressBean implements Serializable { @Inject private CurrentUserBean currentUserBean; @Inject private UserService userService; private Address deliveryAddress = new Address(); private Address billingAddress = new Address(); private boolean copyBillingAddress; public AddressBean() { } public boolean isCopyBillingAddress() { return copyBillingAddress; } public void setCopyBillingAddress(boolean copyBillingAddress) { this.copyBillingAddress = copyBillingAddress; } public String saveAddress() { if (copyBillingAddress) { deliveryAddress = new Address(billingAddress); } User user = currentUserBean.getUser(); if (!billingAddress.isSame(user.getBillingAddress())) { user.setBillingAddress(billingAddress); } if (!deliveryAddress.isSame(user.getDeliveryAddress())) { user.setDeliveryAddress(deliveryAddress); } currentUserBean.setUser(userService.save(user)); return "/checkout.xhtml"; } public CurrentUserBean getCurrentUserBean() { return currentUserBean; } public void setCurrentUserBean(CurrentUserBean currentUserBean) { this.currentUserBean = currentUserBean; } public Address getDeliveryAddress() { return deliveryAddress; } public void setDeliveryAddress(Address deliveryAddress) { this.deliveryAddress = deliveryAddress; } public Address getBillingAddress() { return billingAddress; } public void setBillingAddress(Address billingAddress) { this.billingAddress = billingAddress; } } ```