Question

I discovered a problem in my little program, and Im wondering if anyone have any tips or advice on how to solve this problem as best as possible.

I have the bean testBean which is in request scope. It contains the following:

public class testBean {

private boolean internal = false; 
private String input = "";

public String internalTrue() {
    System.out.println("Set internal true");
    setInternal(true);
    return null;
}
public String submitForm() {
    System.out.println("");
    return null;
}
public boolean isInternal() {
    return internal;
}
public void setInternal(boolean internal) {
    this.internal = internal;
}
public String getInput() {
    return input;
}
public void setInput(String input) {
    this.input = input;
}

}

My file welcomeJSF.jsp contains this:

    <f:view>
        <h:form>
            <h:commandButton value="Set internal true" action="#{testBean.internalTrue}" />
        </h:form>
        <h:panelGrid columns="1" rendered="#{testBean.internal}">
            <h:form>
                <h:outputText value="JavaServer Faces" /><h:inputText value="#{testBean.input}" />
                <h:commandButton value="Go" action="#{testBean.submitForm}" />
            </h:form>
        </h:panelGrid>
    </f:view>

When I run the application Im presented with the button "Set internal true". I click it and Im presented with the form where I have the button "Go". Clicking "Go" does not trigger the method in my bean, most likely because of the field actually not being rendered on the server anymore, and thus it wont run the method. Is there any smart solutions to this?

In advance, thanks for your time.

Was it helpful?

Solution

The children of the panel will never decode input because its rendered attribute always evaluates to false during the APPLY REQUEST VALUES phase. This is a sensible thing to do from a security point of view.

alt text
(source: ibm.com)


One thing you could do is take advantage of the fact that JSF components maintain state for the lifetime of the view.

The new bean:

public class TestBean {

  private String input = null;
  private UIComponent panel;

  public String internalTrue() {
    panel.setRendered(true);
    return null;
  }

  public String submitForm() {
    panel.setRendered(false);
    System.out.println("submitForm");
    return null;
  }

  public UIComponent getPanel() { return panel; }
  public void setPanel(UIComponent panel) { this.panel = panel; }

  public String getInput() { return input; }
  public void setInput(String input) { this.input = input; }

}

The new view bound to the bean:

  <f:view>
    <h:form>
      <h:commandButton value="Set internal true"
        action="#{testBean.internalTrue}" />
    </h:form>
    <h:panelGrid binding="#{testBean.panel}" columns="1"
      rendered="false">
      <h:form>
        <h:outputText value="JavaServer Faces" />
        <h:inputText value="#{testBean.input}" />
        <h:commandButton value="Go" action="#{testBean.submitForm}" />
      </h:form>
    </h:panelGrid>
  </f:view>

Using the binding attribute on the panelGrid will cause setPanel to be called when the view is created/restored.


Note that you may have some testing to do depending on how your implementation's and/or libraries' StateManager stores views between requests (which may in turn be affected by the javax.faces.STATE_SAVING_METHOD init parameter). The view might be stored in a hidden field in the form, in the session keyed to the view ID (which may cause collisions with multiple browser windows), in the session keyed to a unique ID created by a GET or JSF navigation, or by some completely custom mechanism. The pluggable nature of the framework makes it versatile, but in this case it means you need to double-check how your implementation behaves.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top