JSF 中的异步验证器

Asynchronous validators in JSF

我有一个包含编辑框和按钮的简单表单:

<h:form id="addForm">
    <h:outputLabel value="Add item here" /><br />
    <p><h:inputText id="itemInput" value="#{myController.itemToAdd}" validator="myValidator" />
    <h:message for="itemInput" /></p>
    <h:commandButton value="Add" action="#{myController.addItemToList}">
        <f:ajax execute="@form" render="@form :addedItems" />
    </h:commandButton>
</h:form>

当用户点击按钮时,一些基本的验证完成,如果一切正常,项目被添加到数据 table:

<h:panelGrid id="addedItems">
    <h:dataTable value="#{myController.itemMap.entrySet()}" var="itemMapEntry" >
        <h:column>
            <f:facet name="header">
                <h:outputText value="Items" />
            </f:facet>
            <h:commandButton value="Remove/Modify" action="#{myController.removeItemFromList(itemMapEntry.getKey())}">
                <f:ajax render=":addedItems :addForm" />
            </h:commandButton>
            <h:outputText value="#{itemMapEntry.getKey()}" />
        </h:column>
        <h:column>
            <f:facet name="action">
                <h:outputText value="" />
            </f:facet>
            <h:outputText value="#{itemMapEntry.getValue().toString()}" id="itemValidationStatus" />
        </h:column>
    </h:dataTable>
</h:panelGrid>

现在,我想要实现的是,当用户输入一个项目时,首先进行初步验证,如果验证成功,则将项目添加到列表一起显示的 table具有验证状态(例如验证、无效、有效)。当项目被添加到 table 时,另一个更耗时的验证开始,当验证完成时 table 中的 itemValidationStatus 被更新。我不想在耗时的验证期间阻止用户。相反,我想允许用户在验证已添加的项目时添加更多项目。

我看到了三种解决方法:

  1. 注册某种会对对象做出反应的 JS 观察器是 正在托管 bean 中更新

  2. 从托管 bean 触发呈现 可能产生一个验证线程,在完成后, 触发渲染

  3. 有一些方法可以通过 JS 异步启动验证和 注册一个将触发渲染的回调函数 或者直接更新值

问题是我在网上找不到任何可以为我指明正确方向的信息。我正在尝试使用纯 JSF(没有 Prime Faces 或类似工具)来解决这个问题。

编辑:

有人建议我提出另一个可能重复的问题(JSF,使用 ajax 定期刷新组件?)。我不是在寻找一种定期轮询的解决方案,而是在基础数据发生变化时进行更新。而且它只会更改一次,因此显而易见的解决方案是事件侦听器或类似的解决方案。当然,这也可以通过定期民意调查来解决,但对于我所追求的来说,这似乎是非常低的水平。

现在我通过以下更改解决了它(受此 JQuery 相关问题 How to trigger JSF render from jQuery 启发):

  1. 我在表格的<f:ajax>标签中添加了onevent="validateItemList"

    <h:form id="addForm">
        <h:outputLabel value="Add item here" /><br />
        <p><h:inputText id="itemInput" value="#{myController.itemToAdd}" validator="myValidator" />
        <h:message for="itemInput" /></p>
        <h:commandButton value="Add" action="#{myController.addItemToList}">
            <f:ajax execute="@form" onevent="validateItemList" render="@form :addedItems" />
        </h:commandButton>
    </h:form>
    
  2. 我添加了一个带有隐藏按钮的隐藏表单,该按钮会触发耗时的验证并重新呈现 table:

    <h:form id="hiddenForm">
        <h:commandButton value="" action="#{myController.validateItemMap}" id="validatorButton" style="display:none">
            <f:ajax execute="@form" render=":addedItems" />
        </h:commandButton>
    </h:form>
    
  3. 我添加了回调JS函数,"pushes"隐藏按钮:

    <script type="text/javascript">
        function validateItemList(data){
            if(data.status == "success"){
                document.getElementById("hiddenForm:validatorButton").click();
            }
        }
    </script>