仅在第一个组件通过验证时有条件地更新第二个组件

Posted

技术标签:

【中文标题】仅在第一个组件通过验证时有条件地更新第二个组件【英文标题】:Conditionally update 2nd component only when first component passes validation 【发布时间】:2018-09-14 13:52:01 【问题描述】:

我有两个 PrimeFaces selectOneMenu 组件。当第一个组件设置为某个值时,我需要第二个组件成为必需的。我使用 Ajax 和绑定在提交第一个组件时更新第二个组件,以便用户在第二个组件的标签旁边看到所需的“*”。这部分很简单。

这是(稍微简化的)代码:

<p:outputLabel id="foolbl" for="foo"
    value="Foo" />
<p:selectOneMenu id="foo" required="true"
    value="#bean.foo" binding="#foobnd">
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItems
    value="#bean.foovalues" />
<p:ajax
    update="@this foolbl bar barlbl"
    process="@this"/> 
</p:selectOneMenu>

<p:outputLabel id="barlbl" for="bar"
    value="Bar" />
<p:selectOneMenu id="bar"
    required="#foobnd.valid and foobnd.value eq 'value1'"
    value="#bean.bar">
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItems
    value="#bean.barValues" />
<p:ajax update="@this barlbl" process="@this" />
</p:selectOneMenu>

它工作正常,但有以下例外:

    用户从 foo 中选择“值 1”。结果:Bean 更新为 foo 并且 bar 变为必需; 用户从栏中选择一些值。结果:bean 更新为 bar; 用户取消选择栏中的值(选择“选择一个”)。结果:验证失败,因为需要 bar。 Bean 未更新; 用户取消选择 foo 中的值(选择“选择一个”)。结果:Bean 更新为 foo。使用之前提交的 bean.bar 值(“值 1”)更新 Bar。

显然,这是按照 JSF 应有的方式工作的。但是,我担心这会导致用户没有注意到问题,并在他不打算这样做时意外地提交了 bean.bar 的值。这是一种边缘情况,但用户可以在 foo 中选择“选择一个”,然后选择“值 1”以外的某个值,从而导致问题。

为了避免这种情况,我可以在 foo 的 ajax 调用的 process 属性中添加 bar,如下:

<p:selectOneMenu id="foo" required="true"
    value="#bean.foo" binding="#foobnd">
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItems
    value="#bean.foovalues" />
<p:ajax
    update="@this foolbl bar barlbl"
    process="@this bar"/> 
</p:selectOneMenu>

这可以防止前面描述的问题,但它也有意想不到的后果,即在 foo 的初始选择上提交 bar 的值,因此将 bar 突出显示为红色以表示验证失败。我不希望这种情况发生。提交 foo 时,我只希望“*”出现在 bar 旁边。我不希望它在验证失败时突出显示。

我已经尝试使用侦听器和客户验证器来解决这个问题,但到目前为止,没有任何东西能正常工作。 resetValues 也不完全符合我的要求,因为我不喜欢简单地重新选择用户刚刚取消选择的值。

我正在使用 PrimeFaces 6

最好的方法是什么?

【问题讨论】:

【参考方案1】:

你的要求是不是有点无意义?如果需要 selectOneMenu foo,则还需要 selectOneMenu bar 在任何情况下。那么,如果选择了 foo,为什么不直接设置 bar 而不是更新它呢?它必须被选中 反正。如果您满足您的要求,选择一个项目后不显示“选择一个”选项怎么样, 因为无论如何用户都必须选择一个选项。如果你仍然坚持你的观点,你可以尝试设置 如果 bar 验证失败并出现类似 PostValidateEventListener 的情况,则 bar 的模型值为 null:

bean 中的方法:

public void resetModelValue(ComponentSystemEvent event) throws AbortProcessingException 
    UIInput input = (UIInput) event.getSource();
    if (input.isValid()) 
        return;
    
    input.getValueExpression("value").setValue(FacesContext.getCurrentInstance().getELContext(), null);

为 bar 注册 PostValidateEventListener:

<p:selectOneMenu id="bar" ...>
    ...
    <f:event type="postValidate" listener="#bean.resetModelValue" />
</p:selectOneMenu>

但是我认为这个解决方案并不能解决你所有的问题。

【讨论】:

见***.com/questions/6642242/…和***.com/questions/11510758/…和primefaces.org/showcase/ui/misc/resetInput.xhtml

以上是关于仅在第一个组件通过验证时有条件地更新第二个组件的主要内容,如果未能解决你的问题,请参考以下文章

更新 JOptionPane 以反映组件状态更改

Apollo 客户端 writeQuery 更新存储,但 UI 组件仅在第二次函数调用后更新

仅在上下文值更新时有条件地重新渲染

运行时错误,但仅在第二个循环中

Libevent 仅在第二个 buffer_write 之后写入套接字

模态仅在第二次单击后显示