【问题标题】:Validation with JSF 2 only wanted on submit仅在提交时才需要使用 JSF 2 进行验证
【发布时间】:2013-01-24 14:23:39
【问题描述】:

我遇到了验证问题,因为我只希望在单击屏幕上的提交按钮时进行验证,而不是在单击另一个按钮时进行。

在显示的页面中option1.faces是主文件option1.xhtml,以及几个包含的文件。以下是来自主页的代码片段和两个包含的文件:

option1.xhtml 中的代码:

<h:inputText size="4" maxlen="5" id="teff1" value="#{option1.teff1}">
<f:validateDoubleRange minimum="#{option1.teff1Min}" maximum="#{option1.teff1Max}"
    disabled="#{simulator.validate}"/>
</h:inputText>

option1.xhtml 中包含的丰富代码0.xhtml:

<h:selectOneMenu id="abundanceSet0" value="#{abundance.abunSet0}" style="height:25px; width:180px;">
<f:selectItems value="#{abundance.abunSetMap}"/>
</h:selectOneMenu>
<p:spacer width="37" height="0"/>
<p:commandButton value="Select Set" actionListener="#{abundance.selectSet0}" update="abundances0"/>

包含在 option1.xhtml 中的 footerButtons.xhtml 中的代码:

<h:message for="teff1" style="color:red"/>

<h:commandButton value="Submit" disabled="#{!login.loggedIn}" action="#{simulator.submit}" onclick="resetForm()"
actionListener="#{simulator.validate}" class="button"/>

来自相应 bean 的代码片段在这里: MyOption1Bean:

@ManagedBean(name="option1")
@SessionScoped
public class MyOption1Bean implements Serializable {

// Lots of other private variables and objects

private String teff1;

private String teff1Min;
private String teff1Max;

// Option 1 constructor to initialze limits
public MyOption1Bean() {
    ResourceBundle bundle = ResourceBundle.getBundle("com.csharp.validation");
    teff1Min = bundle.getString("teff1Min");
    teff1Max = bundle.getString("teff1Max");
}

public String getTeff1() {
    return teff1;
}

public void setTeff1(String teff1) {
    this.teff1 = teff1;
}

// Lots of getters, setters, methods, etc.
}

MyAbundanceBean:

@ManagedBean(name="abundance")
@SessionScoped
public class MyAbundanceBean implements Serializable {

// Lots of other private variables and objects


public String getAbunSet0() {
    return abunSet[0];
}

public void setAbunSet0(String abunSet) {
    this.abunSet[0] = abunSet;
}


public Map<String,String> getAbunSetMap() {
    return abunSetMap;
}


public void selectSet0(ActionEvent e) {
    selectSet(0);
}

// Lots of getters, setters, methods, etc.

}

MySimulatorBean:

@ManagedBean(name="simulator")
@SessionScoped
public class MySimulatorBean implements Serializable {

// Lots of other private variables and objects

private boolean validate;

// When validate is true disabled is false so validation takes place.
public boolean isValidate() {
    return !validate;
}

// When navigating away from the home page to one of the options, reset the error
// and validate flags.
public void resetError(ActionEvent event) {
    error = false;
    validate = false;
}

// On clicking "Submit" this enables the validate flag.
public void validate(ActionEvent event) {
    validate = true;
}

// On clicking "Submit" this gets the user's input, and if succesful sends it to an output file then
// navigate to a "Success" page, otherwise return to the original page.
public String submit() {

    // Code to check for errors and output data to a file.

}

// Lots of getters, setters, methods, etc.
}

在option1(xhtml 和bean 文件)中,用户输入teff1 的值,该值必须介于teff1Min 和teff1Max 之间,该值是从属性文件中获得的。这可以正常工作,如果teff1 的值未给出或超出范围,则单击footerButtons.xhtml 中给出的“提交”按钮时,提交失败,并且&lt;h:message/&gt; 标签显示错误。

但是,在点击“提交”之前,如果teff1的输入字段为空或有错误的值, 包含的abundances0.xhtml 中的&lt;p:commandButton value="Select Set" .../&gt; 不起作用。它应该使用所选菜单更新显示,否则它会这样做。我设置了immediate &lt;p:commandButton value="Select Set" /&gt; 到 true 的属性,但它仍然不起作用。我只希望在单击“提交”按钮时进行验证,而不是其他任何内容。

我尝试了另一种方法:模拟器 bean 中的标志 validate 用于禁用验证,直到需要它为止。即访问option1页面时为false,禁用为true,直到点击提交按钮才进行验证,此时设置为true,所以禁用为@ 987654344@。不幸的是,这不起作用,因为 JSF 认为页面是有效的,并在执行验证之前离开它。尽管在模拟器 bean 中 validate() 是在 submit() 之前执行的。这可以通过在每个文件中插入打印语句来确认。

有人知道发生了什么吗?是否有一种简单的方法可以确保仅在单击提交按钮时才进行验证?否则显示屏被锁定,我无法使其他按钮工作。


非常感谢您的澄清,我完全按照您的建议做了。我做了以下事情:

首先,我将 immdiate="true" 放在命令按钮中,该按钮在我的丰度0.xhtml 文件中选择一个菜单:

<p:commandButton value="Select Set" actionListener="#{abundance.selectSet0}" update="abundances0" immediate="true"/>

然后我更改了我的丰富 bean java 文件中的操作:

public void selectSet0(ActionEvent e) {
    selectSet(0);
    FacesContext.getCurrentInstance().renderResponse(); 
}

但它仍然不起作用。如果我单击该按钮,除非在 option1.xhtml 文件开头的 teff1 输入字段中已经存在有效值,否则不会发生任何事情。我需要这个按钮和其他类似的按钮一起工作,无论输入字段中有什么,直到单击提交按钮。据我所知,我做的一切都是正确的。

顺便说一句,我正在使用 JSF 2.0 与 PrimeFaces 3.4.2 和 Eclipse Indigo。

【问题讨论】:

  • 如果以下答案之一解决了问题,请使用复选标记接受。

标签: validation jsf primefaces


【解决方案1】:

&lt;p:commandButton&gt; 默认处理整个表单,如process="@form"。

您需要告诉它只处理自己,如process="@this"。

<p:commandButton ... process="@this" />

这样,同一表单中的所有输入组件都不会被处理(转换/验证/更新)。

【讨论】:

    【解决方案2】:

    首先,JSF 中的验证是在 Faces 生命周期之一中执行的,更具体地说,它是在 PROCESS_VALIDATIONS 阶段完成的。 跳过验证的唯一方法是指示 Faces 的生命周期跳过该阶段。

    在 JSF 中,输入和命令组件有一个 immediate 属性,这意味着那些具有 true 值的组件将在 APPLY_REQUEST_VALUES 阶段进行处理,而不是经历整个 Faces 的生命周期。

    行为因组件类型而略有不同:

    • 带有immediate="true" 的输入组件将在APPLY_REQUEST_VALUES 阶段而不是PROCESS_VALIDATION 阶段验证。
    • 带有immediate="true" 的命令组件将在APPLY_REQUEST_VALUES 阶段而不是INVOKE_APPLICATION 阶段执行。

    因此,要跳过验证,一种可能的方法是使用 &lt;h:commandButton /&gt; 和 immediate="true",然后在支持 bean 端调用 FacesContext.getCurrentInstance().renderResponse() 或 FacesContext.getCurrentInstance().requestComplete() 来告诉 Faces 跳过剩余的生命周期阶段.

    所以,在您的select0 方法中应该是:

    public void selectSet0(ActionEvent e) {
        selectSet(0);
        FacesContext.getCurrentInstance().renderResponse(); // skip the remaining phases and go straight to RENDER_RESPONSE
    }
    

    注意:请记住,当使用 immediate 命令提交表单时,将触发所有 immediate 命令中的验证该表格的输入。

    【讨论】:

    • 您好,我将立即输入组件设置为 true,并将 FacesContext 添加到我的操作中: public void selectSet0(ActionEvent e) { selectSet(0); FacesContext.getCurrentInstance().responseComplete(); } 但它仍然不起作用。
    • @csharp 如果您的输入组件将immediate 设置为true,那么无论如何它都会验证。它必须是您的命令组件,而不是输入组件,然后指示 Faces 跳过其余阶段。刚刚编辑了我的答案以使其更清晰
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多