2 Replies Latest reply on Oct 1, 2011 10:33 PM by akaine

    Solution optimization to the "Local values reset sad story"

    akaine

      Hello

      Most of those who tried to fought this problem are familiar with this page: http://ishabalov.blogspot.com/2007/08/sad-story-about-uiinput.html.

       

      The simplest solution normally would be to call setValue(null) and setSubmittedValue(null) methods of the components successfully resetting the local values. I find the alternative offered in the article not very usable since web application forms are normally much bigger and more complicated than the given example.

       

      After playing a bit with possible ways the quickest one was:

       

      1. Assign ids to all input-based components (JSF/RF APIs help here a lot: no reflection needed since all input components come from javax.faces.component.UIInput class)

      2. A small utility method which would reset our fields:

      private static UIComponent findComponent(UIComponent component, String simpleId){
          if(simpleId.equals(component.getId())){
              return component;
          }
          Iterator<UIComponent> children = component.getFacetsAndChildren();
          while(children.hasNext()){
              UIComponent targetComponent = findComponent(children.next(),simpleId);
              if(targetComponent!=null){
                  return targetComponent;
              }
          }
          return null;
      }
      
      public static void resetComponent(FacesContext context, String simpleId){
          UIInput component = (UIInput)findComponent(context.getViewRoot(),simpleId);
          component.setValue(null);
          component.setSubmittedValue(null);
      }
      

      3. Call the utility method for each damn field in the form we want to be clean.

       

      The problem here is that the process is too manual, every field has to have an id and it's even worse on Java level where we have to call the method for every field increasing the code amount and making the application less flexible since the ids have to appear on both sides.

       

      My actual question was:

      Is there any simpler alternatives to this approach? Maybe even by optimizing the same idea, or something completely different. Form children iteration wouldn't do the trick, since most of forms are too complex to have all the fields just on one level.

        • 1. Re: Solution optimization to the "Local values reset sad story"
          akaine

          Partially solved with:

          public static void resetComponent(UIComponent c){
              if(c instanceof UIInput){
                  UIInput uiInput = (UIInput)c;
                  uiInput.setValue(null);
                  uiInput.setSubmittedValue(null);
              }
          
              Iterator<UIComponent> children = c.getFacetsAndChildren();
              while(children.hasNext()){
                  resetComponent(children.next());
              }
          }
          

          where the initial parameter is the form in question component.

          • 2. Re: Solution optimization to the "Local values reset sad story"
            akaine

            I know it's a necromancy, still I'd like to share the final solition I made several days after the last post since many people keep asking "what the heck":

             

            import java.util.Iterator;
            import javax.faces.component.UIComponent;
            import javax.faces.component.UIInput;
            import javax.faces.context.FacesContext;
            
            public class UtilsJSF{
            
                private static UtilsJSF util;
            
                private UtilsJSF(){}
            
                public static UtilsJSF getInstance(){
                    return util == null ? new UtilsJSF() : util;
                }
            
                /**
                 * Resets all UIInput based elements values contained inside the form
                 * 
                 * @param context    current instance of the FacesContext
                 * @param componentId    id of the form to clean
                 * @see UIInput
                 */
                public static void resetFormComponent(FacesContext context, String componentId){
                    UIComponent form = findComponent(context.getViewRoot(),componentId);
                    resetComponent(form);
                }
            
                public static void resetComponent(FacesContext context, String componentId){
                    UIInput component = (UIInput)findComponent(context.getViewRoot(),componentId);
                    component.setValue(null);
                    component.setSubmittedValue(null);
                }
            
                private static UIComponent findComponent(UIComponent c, String id){
                    if(id.equals(c.getId())){
                        return c;
                    }
                    Iterator<UIComponent> kids = c.getFacetsAndChildren();
                    while(kids.hasNext()){
                        UIComponent found = findComponent(kids.next(), id);
                        if(found != null){
                            return found;
                        }
                    }
                    return null;
                }
            
                private static void resetComponent(UIComponent c){
                    if(c instanceof UIInput){
                        UIInput uiInput = (UIInput)c;
                        uiInput.setValue(null);
                        uiInput.setSubmittedValue(null);
                    }
            
                    Iterator<UIComponent> children = c.getFacetsAndChildren();
                    while(children.hasNext()){
                        resetComponent(children.next());
                    }
                }
            }
            

             

            Hope this helps