Java Server Faces продолжает отображать старые значения после сбоя фазы проверки (игнорируя настройки actionListeners)) - PullRequest
1 голос
/ 12 июня 2011

Я хотел бы попросить некоторой помощи в понимании конкретного поведения, которое JSF показывает на этапе проверки терпит неудачу.

Я использую:

  • Tomcat 7.0.2
  • JSF 1.2_12
  • RichFaces 3.3.3

Описание проблемы.

Я написал форму с 4 полями ввода: inputText и 3 selectOneMenu. Требуется inputText в то время как selectOneMenus не требует никакой проверки. Прикрепленный к первому selectOneMenu (строка 32), является тегом a4j: support, так что всякий раз, когда происходит событие изменения, список элементов второго и третий selectOneMenu (строки 44 и 58) заполнены правильно. В частности, после загрузки В двух списках элементов метод вызывает значение второго и третьего selectOneMenu к нулю. Этот механизм, кажется, работает нормально, пока я не отправлю форму без заполнения ввода текст: как и ожидалось, проверка JSF не удалась, но когда я изменил значение первого selectOneMenu, на странице отображаются значения, указанные до того, как проверка JSF не удалась в течение третий selectOneMenu (обратите внимание, что actionListener по-прежнему вызывается и значения второго и третье selectOneMenu по-прежнему обнуляется).

Поскольку я использую простой PhaseListener, я заметил следующее: перед неудачей проверки JSF каждый раз, когда я изменяю значение первого selectOneMenu, JSF life цикл всегда вызывает метод get для второго и третьего selectOneMenu во время рендеринга Фаза ответа. Таким образом, JSF может «видеть», что эти значения были установлены в нуль во время этап вызова приложения. После сбоя проверки JSF перестает вызывать эти геттеры, когда я изменяю значение первого selectOneMenu.

Вот мой взгляд

<?xml version='1.0' encoding='UTF-8' ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:a4j="http://richfaces.org/a4j"
      xmlns:rich="http://richfaces.org/rich">

<head>
  <title>Prove Rich</title>
</head>

<body>

  <h2>Prove Rich</h2>

  <f:view>

  <a4j:outputPanel ajaxRendered="true">
    <h:messages style="color:red" />
  </a4j:outputPanel>

  <h:form>

  <p>
    Input required: <h:inputText value="#{provaProbReplyBean.inputRequired}" required="true" />
  </p>

  <p>
    <h:outputText value="Scegli il canale:" />
    <h:selectOneMenu value="#{provaProbReplyBean.canale}">

       <f:selectItem itemLabel="--" itemValue="" />
       <f:selectItem itemLabel="Profamily" itemValue="Profamily" />
       <f:selectItem itemLabel="Captive" itemValue="Captive" />

       <a4j:support event="onchange" action="#{provaProbReplyBean.caricaProcBanche}" ajaxSingle="true" reRender="procedure, banche" />
    </h:selectOneMenu>
  </p>

  <p>
    <h:outputText value="Scegli la procedura:" />
    <h:selectOneMenu id="procedure" value="#{provaProbReplyBean.procedura}">

       <f:selectItem itemLabel="--" itemValue="" />

       <f:selectItems value="#{provaProbReplyBean.procedureList}" />

       <!-- immediately save the current value -->
       <a4j:support event="onchange" ajaxSingle="true" />

    </h:selectOneMenu>
  </p>

  <p>
    <h:outputText value="Scegli la banca:" />
    <h:selectOneMenu id="banche" value="#{provaProbReplyBean.banca}">

       <f:selectItem itemLabel="--" itemValue="" />

       <f:selectItems value="#{provaProbReplyBean.bancheList}" />

       <!-- immediately save the current value -->
       <a4j:support event="onchange" ajaxSingle="true" />

    </h:selectOneMenu>
  </p>

  <p><h:commandButton value="Submit" /></p>

  </h:form>

  </f:view>

</body>

</html>

А вот и моя модель:

public class ProvaProbReply {

    private String inputRequired;

    private String canale;
    private String procedura;
    private String banca;

    private Map<String, List<SelectItem>> canaliProc = new HashMap<String, List<SelectItem>>();
    private Map<String, List<SelectItem>> canaliBanche = new HashMap<String, List<SelectItem>>();

    private List<SelectItem> procedureList = new ArrayList<SelectItem>();
    private List<SelectItem> bancheList = new ArrayList<SelectItem>();

    public ProvaProbReply() {

        List<SelectItem> l = new ArrayList<SelectItem>();
        l.add(new SelectItem("Cessione del quinto"));
        l.add(new SelectItem("Credito al consumo"));
        l.add(new SelectItem("Mutui"));

        canaliProc.put("Profamily", l);

        l = new ArrayList<SelectItem>();
        l.add(new SelectItem("Credito al consumo"));

        canaliProc.put("Captive", l);

        l = new ArrayList<SelectItem>();

        canaliBanche.put("Profamily", l);

        l = new ArrayList<SelectItem>();
        l.add(new SelectItem("BDL"));
        l.add(new SelectItem("BM"));
        l.add(new SelectItem("BPM"));
        l.add(new SelectItem("CRA"));

        canaliBanche.put("Captive", l);
    }

    public String getInputRequired() {

        return inputRequired;
    }

    public void setInputRequired(String ir) {

        inputRequired = ir;
    }

    public String getCanale() {

        return canale;
    }

    public void setCanale(String c) {

        canale = c;
    }

    public String getProcedura() {

        System.out.println("\ngetProcedura called\n");
        return procedura;
    }

    public void setProcedura(String p) {

        procedura = p;
    }

    public String getBanca() {

        System.out.println("\ngetBanca called\n");
        return banca;
    }

    public void setBanca(String b) {

        banca = b;
    }

    public List<SelectItem> getProcedureList() {

        return procedureList;
    }

    public List<SelectItem> getBancheList() {

        return bancheList;
    }

    public String caricaProcBanche() {

        System.out.println("\nListener called\n");

        procedureList.clear();
        bancheList.clear();

        if(canale != null && !canale.equals("")) {

            procedureList.addAll(canaliProc.get(canale));
            bancheList.addAll(canaliBanche.get(canale));
        }

        System.out.println("BEFORE setting:\n");

        System.out.println("\nProcedura: "+procedura+"\n");
        System.out.println("Banca: "+banca+"\n");

        procedura = null;
        banca = null;

        System.out.println("\n\n\nAFTER setting:\n");

        System.out.println("\nProcedura: "+procedura+"\n");
        System.out.println("Banca: "+banca+"\n");

        return "";
    }
}

1 Ответ

2 голосов
/ 14 июня 2011

Похоже, вы наблюдаете ожидаемое поведение типов EditableValueHolder.

Если проверка или преобразование типов не пройдены, форма будет перерисована в том состоянии, в котором она была отправлена.Это указывается в документации для фазы Применить значения запроса (спецификация JSF 2):

В конце этой фазы все EditableValueHolder компоненты в дереве компонентовбудет обновлен новыми представленными значениями, включенными в этот запрос (или будет сохранено достаточно данных для воспроизведения неверного ввода, если были ошибки преобразования).

Если преобразование илипроверка не пройдена, фаза Update Model Values ​​ не будет запущена (ни один из сеттеров не будет вызываться для bean-компонентов.) Если пользователь только что отправил сложную форму, он не будет ожидать, что все поля будутстер, потому что один был неправ.Средства визуализации испускают значение, предоставленное пользователем, и не вызывают геттеры (см. isValid() и getSubmittedValue()).

...