1 2 Previous Next 23 Replies Latest reply: Dec 14, 2011 3:05 PM by henk de boer Go to original post RSS
  • 15. Re: Validation and refresh problems...
    henk de boer Master

    ilya_shaikovsky wrote:

     

    It's better to resolve this at JSF spec level by filling RFC there. Our approach is not to change functionality described in JSF spec but extend using standard extension points. From the point of view of your case it sounds reasonable. But as the submitted value needed in order to fire valueChangeEvent - such functionality will conflict with standard JSF functionality in its current state.

     

    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...
    Nick Belaevski Master

    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...
    henk de boer Master

    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...
    arjan tijms Novice

    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 Newbie

    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.

     

     

    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 &amp;&amp; !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());
                   }          
    
              }
         }
    
    }
    

     

     

    Julien

  • 20. Re: Validation and refresh problems...
    Markus Staab Newbie

    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...
    henk de boer Master

    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...
    Rudra Garnaik Newbie

    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...
    henk de boer Master

    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.

1 2 Previous Next