当前位置: 首页 > 面试题库 >

使用p:calendar在jsf h:datatable中进行跨字段验证

陶俊晤
2023-03-14
问题内容

我注意到有人问过这个问题,但是没有正确回答。

我有一个数据表,其中有两列 开始日期结束日期
。两者都包含总理字符p:calendar控件。我需要确保每一行中column1中的日期都不晚于column2中的日期。我想将其绑定到JSF验证框架中,但是遇到了麻烦。

我尝试将数据表标记为rowStatePreserved =“
true”,这使我能够获取值,但是还是有些错误,因为当它失败时,第一行中的所有值都会覆盖所有其他值。我在做什么错,还是应该使用完全不同的策略?

xhtml代码

    <h:form>
 <f:event type="postValidate" listener="#{bean.doCrossFieldValidation}"/>
       <p:dataTable id="eventDaysTable" value="#{course.courseSchedules}" var="_eventDay" styleClass="compactDataTable"
                                 >
                        <p:column id="eventDayStartColumn">
                            <f:facet name="header">
                                Start
                            </f:facet>
                            <p:calendar id="startDate" required="true"  value="#{_eventDay.startTime}" pattern="MM/dd/yyyy hh:mm a"/>
                        </p:column>
                        <p:column id="eventDayEndColumn">
                            <f:facet name="header">
                                End
                            </f:facet>
                            <p:calendar id="endDate" required="true"  value="#{_eventDay.endTime}" pattern="MM/dd/yyyy hh:mm a"/>
                        </p:column>                                        
                    </p:dataTable>
        </h:form>

验证码

 public void doCrossFieldValidation(ComponentSystemEvent cse) {


        UIData eventsDaysStable = (UIData) cse.getComponent().findComponent("eventDaysTable");

        if (null != eventsDaysStable && eventsDaysStable.isRendered()) {

            Iterator<UIComponent> startDateCalendarIterator = eventsDaysStable.findComponent("eventDayStartColumn").getChildren().iterator();
            Iterator<UIComponent> endDateCalendarIterator = eventsDaysStable.findComponent("eventDayEndColumn").getChildren().iterator();

            while (startDateCalendarIterator.hasNext() && endDateCalendarIterator.hasNext()) {
                org.primefaces.component.calendar.Calendar startDateComponent = (org.primefaces.component.calendar.Calendar) startDateCalendarIterator.next();
                org.primefaces.component.calendar.Calendar endDateComponent = (org.primefaces.component.calendar.Calendar) endDateCalendarIterator.next();

                Date startDate = (Date) startDateComponent.getValue();
                Date endDate = (Date) endDateComponent.getValue();


                if (null != startDate && null != endDate && startDate.after(endDate)) {
                    eventScheduleChronologyOk = false;
                    startDateComponent.setValid(false);
                    endDateComponent.setValid(false);
                }

            }

            if (!eventScheduleChronologyOk) {
                showErrorMessage(ProductManagementMessage.PRODUCT_SCHEDULE_OUT_OF_ORDER);
            }

        }

    }

问题答案:

我究竟做错了什么

以非标准的JSF方式在数据表的上下文之外执行验证。仅
您(或JSF)在数据表上迭代时,行数据才可用。实际上<p:calendar>,每列中只有一个组件具有多个不同的状态,具体取决于当前的数据表迭代回合。当您不遍历数据表时,这些状态不可用。然后,您只会获得null价值。

从技术上讲,到目前为止,您使用不同的验证方法,您应该visitTree()UIData组件上调用方法并在VisitCallback实现中执行工作。这将遍历数据表。

例如,

dataTable.visitTree(VisitContext.createVisitContext(), new VisitCallback() {
    @Override
    public VisitResult visit(VisitContext context, UIComponent component) {
        // Check if component is instance of <p:calendar> and collect its value by its ID.

        return VisitResult.ACCEPT;
    }
});

这只是笨拙。这为您提供了每一行,您需要自己维护和检查行索引并收集值。注意,调用UIInput#setValid()也应该在实现内部完成VisitCallback

还是我应该使用完全不同的策略?

是的,请使用标准Validator的标准JSF方法。您可以将一个组件作为另一组件的属性来传递。

例如

<p:column>
    <p:calendar binding="#{startDateComponent}" id="startDate" required="true"  value="#{item.start}" pattern="MM/dd/yyyy hh:mm a"/>
</p:column>
<p:column >
    <p:calendar id="endDate" required="true"  value="#{item.end}" pattern="MM/dd/yyyy hh:mm a">
        <f:validator validatorId="dateRangeValidator" />
        <f:attribute name="startDateComponent" value="#{startDateComponent}" />
    </p:calendar>
</p:column>

@FacesValidator("dateRangeValidator")
public class DateRangeValidator implements Validator {

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        if (value == null) {
            return; // Let required="true" handle.
        }

        UIInput startDateComponent = (UIInput) component.getAttributes().get("startDateComponent");

        if (!startDateComponent.isValid()) {
            return; // Already invalidated. Don't care about it then.
        }

        Date startDate = (Date) startDateComponent.getValue();

        if (startDate == null) {
            return; // Let required="true" handle.
        }

        Date endDate = (Date) value;

        if (startDate.after(endDate)) {
            startDateComponent.setValid(false);
            throw new ValidatorException(new FacesMessage(
                FacesMessage.SEVERITY_ERROR, "Start date may not be after end date.", null));
        }
    }

}

由于两个组件都在同一行中,因此每次调用此验证器时,startDateComponentwill都会自动“自动”提供正确的值getValue()。请注意,该验证器在数据表外部也可以重用,而您的初始方法则不是。

或者,您可以将OmniFaces
<o:validateOrder>用作完整的解决方案。它的展示实例甚至展示<p:calendar><p:dataTable>



 类似资料:
  • 问题内容: Hibernate Validator 4.x中是否有跨域验证的实现(或第三方实现)?如果没有,实现跨域验证器的最干净方法是什么? 例如,如何使用API​​来验证两个bean属性是否相等(例如,验证密码字段与密码验证字段匹配)。 在注解中,我期望这样的东西: 问题答案: 每个字段约束都应由不同的验证者注释处理,换句话说,不建议对一个字段进行其他字段的验证注释检查。跨领域验证应在课程级别

  • 问题内容: 我正在使用此答案中指定的相等性验证表单上的两个字段“ password”和“ confirmPassword” 。以下是 约束描述符(验证器接口)。 以下是 约束验证器 (实现类)。 以下是与JSP页面映射的验证器bean(由标记指定)。 更新 一切正常,并按预期进行验证。剩下的一件事就是在未显示的类上方显示指定的错误消息,即 只有一个问题: 发生验证冲突时如何在JSP页面上显示错误消

  • 我如何验证一个列表的值跨字段,其中至少一个单一的值必须设置(不是零) 我需要验证至少有一个字段被输入(例如总数不是零) 我遇到的问题是,当任何一个字段发生更改时,validator::total_cost不会重新评估所有正在验证的字段。 在“任意”输入中键入正确的值需要告诉“所有”其他输入,以便根据新的计算字段重新估价! 任何帮助都将不胜感激。 (我的电视机大得多) 我正在使用的标记 AnyVal

  • 列表字段中bean的条件验证。 我对bean验证有一个小问题。我想做一个条件验证,但是被验证的类有一个必须被验证的bean列表作为字段,这些bean的一些字段必须被条件验证。这里有一个示例代码: 我可以在子bean上做一个循环,并分别验证每个子bean,但错误中的路径是错误的 另外,我可以使用这样的解决方案:使用Hibernate Validator(JSR 303)进行跨域验证,但它似乎弄乱了与

  • 我想让成为只读的,这样用户就只能因为这个问题从日历中选择一个日期(但这不是一个解决方案)。 为此,我正在执行,

  • 问题内容: 我正在构建一个登录表单复合组件。使用它的页面将传递一个事件处理程序,该处理程序将验证用户名和密码。通常,当我们通过进行跨字段验证时(不使用复合组件),事件处理程序必须按名称查找字段的组件。验证者最好不要这样做,因为这些是应该抽象的组件的内部细节。 知道如何在不知道复合组件内部细节的情况下如何在处理程序中获取用户名和密码字段的转换值吗? 更新: 这样做的目的不是完全避免按名称查找组件,而