title: JSF 2 -- Save All Valid Component Values
body: <p>I have a requirement to create a javascript function that when invoked will save all of the valid components on a JSF 2.0 form. Since the complete form will never be valid as a whole I need to figure out a way to run the lifecycle per component so that if the validation phase is successful the model will be updated and eventually saved. </p>
  
  <p>Ideally, this needs to be a single ajax request as iterating over each component with a separate ajax request would be painfully inefficient. </p>
  
  <p>Has anyone solved the problem before? If not could you give me some pointers on possible implementations?</p>
  
  <p><strong>Edit:</strong></p>
  
  <p>Here's what I have that seems to be working well so far:</p>
  
  <pre><code>@ManagedBean(name = "partialAppSaveBean")
  @RequestScoped
  public class PartialAppSaveBean implements Serializable {
  
      protected static final Logger LOGGER = LoggerFactory.getLogger(PartialAppSaveBean.class);
      private static final long serialVersionUID = 1L;
  
      /**
       * Save any valid Application values
       *
       * @param event
       */
      public void saveData(AjaxBehaviorEvent event) {
          final FacesContext context = FacesContext.getCurrentInstance();
  
          UIForm form = getParentForm(event.getComponent());
          Set&lt;VisitHint&gt; hints = EnumSet.of(VisitHint.SKIP_UNRENDERED);
  
          form.visitTree(VisitContext.createVisitContext(context, null, hints), new VisitCallback() {
  
              @Override
              public VisitResult visit(VisitContext context, UIComponent component) {
              if (component instanceof UIInput) {
                  UIInput input = (UIInput) component;
                  input.validate(context.getFacesContext());
  
                  if (input.isValid() &amp;&amp; input.getValue() != null) {
                      ValueExpression valueExpression = input.getValueExpression("value");
  
                      if (valueExpression != null
                              &amp;&amp; valueExpression.getExpressionString() != null) {
                          try {
                              valueExpression.setValue(context.getFacesContext().getELContext(), input.getValue());
                          } catch (Exception ex) {
                              LOGGER.error("Expression [ " + valueExpression.getExpressionString() + 
                                      "] value could not be set with value [" + input.getValue() + "]", ex);
                          }                            
                      }
                  }
              }
  
              return VisitResult.ACCEPT;
              }
          });
  
          //Save data here
      }
  
      /**
       * Returns the parent form for this UIComponent
       * 
       * @param component
       * @return form
       */
      private static UIForm getParentForm(UIComponent component) {
          while (component.getParent() != null) {
              if (component.getParent() instanceof UIForm) {
                  return (UIForm) component.getParent();
              } else {
                  return getParentForm(component.getParent());
              }
          }
  
          return null;
      }
  
  }
  </code></pre>
  
  <p>Invoked with something like:</p>
  
  <pre><code>&lt;h:commandButton
      id="saveData"&gt;
      &lt;f:ajax listener="#{partialAppSaveBean.saveData}" execute="@form" immediate="true" onevent="onPartialSave" /&gt;
  &lt;/h:commandButton&gt;
  </code></pre>