-
15. Re: Validation and refresh problems...
henk53 Jan 19, 2010 1:06 PM (in response to ilya_shaikovsky)ilya_shaikovsky wrote:
I understand completely and I fully respect and applaud your decision to adhere to the JSF spec as much as possible. This should be indeed be the default as an absolute first priority.
However, giving the user the option to explicitly override some behavior might be helpful here. As it is, JSF itself allows many of its parts to be replaced or augmented by the user if the user chooses to do so, possibly breaking compatibility at the user's own risk. Many third party libraries also have options for this (of course, never as a default).
An option for RichFaces to force a re-rendering from source, with a clear warning that this might conflict with other JSF functionality, might not be that bad. By default the user would user the reRender attribute and only when absolutely necessary, would he use forceReRender. The word "force" already communicates that something out of the ordinary is happening.
For the ones interested in it, I did wrote a small fairly universal actionlistener that one can include inside an a4j:actionLink or button:
package com.something.faces; import java.util.Set; import javax.faces.component.EditableValueHolder; import javax.faces.component.UIComponent; import javax.faces.component.UIForm; import javax.faces.context.FacesContext; import javax.faces.event.AbortProcessingException; import javax.faces.event.ActionEvent; import javax.faces.event.ActionListener; import org.ajax4jsf.context.AjaxContext; public class A4JFormReset implements ActionListener { @Override public void processAction(ActionEvent event) throws AbortProcessingException { FacesContext facesContext = FacesContext.getCurrentInstance(); AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext); UIComponent root = facesContext.getViewRoot(); ajaxContext.addRegionsFromComponent(event.getComponent()); Set<String> ids = ajaxContext.getAjaxAreasToRender(); for (String id : ids) { UIComponent form = findParentForm(root.findComponent(id)); if (form != null) { clearComponentHierarchy(form); } } } public UIComponent findParentForm(UIComponent component) { if (component instanceof UIForm) { return component; } if (component == null) { return null; } return findParentForm(component.getParent()); } public void clearComponentHierarchy(UIComponent pComponent) { if (pComponent instanceof EditableValueHolder) { EditableValueHolder editableValueHolder = (EditableValueHolder) pComponent; editableValueHolder.setSubmittedValue(null); editableValueHolder.setValue(null); editableValueHolder.setValid(true); } for (UIComponent child : pComponent.getChildren()) { clearComponentHierarchy(child); } } }
This can be used on a JSF page like this:
<a4j:commandLink value="test" action="#{bean.someMethod}" reRender="someID"> <f:actionListener type="com.something.faces.A4JFormReset" /> </a4j:commandLink>
Since the actionListener fires before the commandLink gets a chance to setup its preRender stuff, I had to call ajaxContext.getAjaxAreasToRender() myself in advance. I hope I don't break anything with it, but I scanned the implementation source and it seems to be harmless. The commandLink will call it again anyway.
I briefly tested this and it seems to work nicely. It's basically the code others have posted but wrapped in a more universal package. Maybe it's also not even needed to clear the whole form but just the target components.
Ilya, if you do see anything really wrong in this code, please let us know.
-
16. Re: Validation and refresh problems...
nbelaevski Jan 19, 2010 1:41 PM (in response to henk53)Hi,
Several corrections:
- Non-rendered components and their children should be skipped
- Facets should be also processed together with children
- "localValueSet" attribute of EditableValueHolder should be also reset (this should be done after resetting "value" attribute, not before!)
- findParentForm(UIComponent) is better to rewrite without recursion for performance improvement
-
17. Re: Validation and refresh problems...
henk53 Jan 19, 2010 2:40 PM (in response to nbelaevski)Several corrections:
- Non-rendered components and their children should be skipped
- Facets should be also processed together with children
- "localValueSet" attribute of EditableValueHolder should be also reset (this should be done after resetting "value" attribute, not before!)
- findParentForm(UIComponent) is better to rewrite without recursion for performance improvement
Wow, thanks a lot. Those are very valuable suggestions. Even though I have been using JSF for some time, I'm not really that knowledgeable with the internals yet. This is the new version with your suggested improvements:
package com.something.faces; import java.util.Iterator; import java.util.Set; import javax.faces.component.EditableValueHolder; import javax.faces.component.UIComponent; import javax.faces.component.UIForm; import javax.faces.context.FacesContext; import javax.faces.event.AbortProcessingException; import javax.faces.event.ActionEvent; import javax.faces.event.ActionListener; import org.ajax4jsf.context.AjaxContext; public class A4JFormReset implements ActionListener { @Override public void processAction(ActionEvent event) throws AbortProcessingException { FacesContext facesContext = FacesContext.getCurrentInstance(); AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext); UIComponent root = facesContext.getViewRoot(); ajaxContext.addRegionsFromComponent(event.getComponent()); Set<String> ids = ajaxContext.getAjaxAreasToRender(); for (String id : ids) { UIComponent form = findParentForm(root.findComponent(id)); if (form != null) { clearComponentHierarchy(form); } } } public UIComponent findParentForm(UIComponent component) { for (UIComponent parent = component; parent != null; parent = parent.getParent()) { if (parent instanceof UIForm) { return parent; } } return null; } public void clearComponentHierarchy(UIComponent pComponent) { if (pComponent.isRendered()) { if (pComponent instanceof EditableValueHolder) { EditableValueHolder editableValueHolder = (EditableValueHolder) pComponent; editableValueHolder.setSubmittedValue(null); editableValueHolder.setValue(null); editableValueHolder.setLocalValueSet(false); editableValueHolder.setValid(true); } for (Iterator<UIComponent> iterator = pComponent.getFacetsAndChildren(); iterator.hasNext();) { clearComponentHierarchy(iterator.next()); } } } }
-
18. Re: Validation and refresh problems...
atijms Jan 22, 2010 6:26 AM (in response to henk53)I tried the action listener and it seems to work very well. Thanks to everyone involved for providing this.
It maybe wouldn't be a bad idea for Rich faces if they shipped something like this action listener with the standard distribution.
-
19. Re: Validation and refresh problems...
julien.dramaix Apr 7, 2010 5:55 AM (in response to atijms)Nice code !! And works perfectly !
My little contribution : avoid to clear two times (or more) the same form if many components of the same form is in the reRender attributes.
{code}
package com.something.faces;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIForm;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
import org.ajax4jsf.context.AjaxContext;
public class A4JFormReset implements ActionListener {
public void processAction(ActionEvent event) throws AbortProcessingException {
FacesContext facesContext = FacesContext.getCurrentInstance();
AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext);
UIComponent root = facesContext.getViewRoot();
ajaxContext.addRegionsFromComponent(event.getComponent());Set<String> ids = ajaxContext.getAjaxAreasToRender();
List<String> formIds = new LinkedList<String>();
for (String id : ids) {
UIComponent form = findParentForm(root.findComponent(id));
if (form != null && !formIds.contains(form.getId())) {
clearComponentHierarchy(form);
formIds.add(form.getId());
}
}
}
public UIComponent findParentForm(UIComponent component) {
for (UIComponent parent = component; parent != null; parent = parent.getParent()) {
if (parent instanceof UIForm) {
return parent;
}
}
return null;
}
public void clearComponentHierarchy(UIComponent pComponent) {
if (pComponent.isRendered()) {
if (pComponent instanceof EditableValueHolder) {
EditableValueHolder editableValueHolder = (EditableValueHolder) pComponent;
editableValueHolder.setSubmittedValue(null);
editableValueHolder.setValue(null);
editableValueHolder.setLocalValueSet(false);
editableValueHolder.setValid(true);
}
for (Iterator<UIComponent> iterator = pComponent.getFacetsAndChildren(); iterator.hasNext();) {
clearComponentHierarchy(iterator.next());
}
}
}
}
{code}
Julien
-
20. Re: Validation and refresh problems...
maggus Aug 8, 2011 9:29 AM (in response to julien.dramaix)Why do you search for the form which holds the component which should be reRendered? why do you afterwards clear this form completly?
why not only searching for the component and clear it (and maybe all child-components and facets which are related to this component)....?
-
21. Re: Validation and refresh problems...
henk53 Aug 8, 2011 5:52 PM (in response to maggus)Markus Staab wrote:
Why do you search for the form which holds the component which should be reRendered? Why do you afterwards clear this form completely?
To be honest, I'm not exactly sure anymore why this was done. I guess it was to keep the whole form in a consistent 'cleared' state, or maybe it would only work if all components were cleared. (anyway, Julien's addition is rather nice, the original code indeed potentially cleared the same form many times over)
Also, in JSF 2.0 and RichFaces 4, the same problem applies but the solution is different. At the very least
AjaxContext
doesn't exist anymore. -
22. Re: Validation and refresh problems...
rngarnaik Dec 14, 2011 12:58 AM (in response to ilya_shaikovsky)JSF 2.0 and Richfaces 4.0 not yet addressed this issue, what is the process to file RFC? Can richfaces guys able to fix this issue with enhanced functionality with a4j components?
Anyway thaks guys for this post, we able to get the temporary solution for this issue .
-
23. Re: Validation and refresh problems...
henk53 Dec 14, 2011 3:05 PM (in response to rngarnaik)Rudra Garnaik wrote:
JSF 2.0 and Richfaces 4.0 not yet addressed this issue, what is the process to file RFC?
There's a public JIRA issue created for it here: http://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1060 The spec lead has just indicated he's open to this.
Can richfaces guys able to fix this issue with enhanced functionality with a4j components?
They should speak for themselves of course, but earlier in this thread they have indicated not being in favor of fixing it, since staying true to the spec is quite important.
-
24. Re: Validation and refresh problems...
marcelkolsteren Jun 19, 2014 5:24 AM (in response to henk53)Finally, JSF contains a fix for this problem, which is part of JSF 2.2. See http://jsflive.wordpress.com/2013/06/20/jsf-22-reset-values/.