在XPage上添加JQuery对话框的方法

时间:2018-01-16 08:13:53

标签: javascript jquery validation dialog xpages

我有一个div,应该表现得像JQuery dialog。在此div中,我输入了一些数据,尝试对其进行验证,并将其保存到数据库中。用户点击时会打开对话框我遇到了3个问题:

1。 JQuery ID的选择器

基本上我们知道如果我们试图找到

 <xp:div id="addingDialog"> 
 </xp:div> 
    使用像这样var dialog = $('#addingDialog')的JQuery选择器 - 它会给我们没有结果,因为XPage中的id是动态计算的。所以我决定使用类(styleClasses,如果你愿意)声明它,就像这样

 <xp:div styleClass="addingDialog"> 
 </xp:div> 
JQuery是这样的:var dialog = $('.addingDialog')。似乎工作,虽然不是很好。

2。点击应该验证它的按钮并制作所有后端内容并不起作用:(

不幸的是,当我点击&#34;添加&#34;按钮(保存的按钮)没有任何反应 - 即使输入正确,即使验证失败并且没有保存任何内容,对话框也会关闭。

所以我找到了一个解决方案 - 不要使用对话框和JQuery。

但这不是正确的解决方案,至少不是这种情况。但即便出现另一个问题 - 验证

有2个对话框:一个用于添加,另一个用于编辑(JQuery不允许只有一个具有不同按钮功能的对话框),两个都有验证,我必须输入一些东西进行编辑才能添加新!最初我认为XPage中的验证工作原理是这样的 - 当用户在相应的 div 检查中点击对应按钮(添加或编辑)所有 inputText 时如果它是正确的 - 验证成功并且后端行动发生。问题是 - 如何让它像这样工作?结果是页面上的每个inputText检查。我不希望它像这样工作(截图不使用JQuery)This is what I see on a page。如果我在编辑对话框中输入任何值,请单击&#34; +添加部分&#34;一切正常。也许完全是因为对话中的这个saving actions没有发生?因为我只打开了一个对话框,但验证&#34;看到&#34;其他隐藏的输入是空的,所以验证失败了吗?这是我的代码

    <xp:div styleClass="dialogAddPart">
    <xp:table>
                <xp:tr>
                <xp:td><xp:label value="Title:" /></xp:td>
                <xp:td>
                <xp:inputText 
                styleClass="doc_field_textinput" id="input_part_title" type="text" size="40" disableClientSideValidation="true" required="true">
                <xp:this.validators>
                <xp:validateRequired
                    message="#{javascript:return('This field is required')}">
                </xp:validateRequired>
                </xp:this.validators>
                </xp:inputText>
                <xp:message id="message15" for="input_part_title"
                                rendered="true" showDetail="false" showSummary="true"
                                style="font-style:italic;background_field-color:rgb(217,234,235);border-color:rgb(102,102,102)">
                </xp:message>
                </xp:td>
                </xp:tr>

                <xp:tr>
                <xp:td><xp:label value="Total:"/></xp:td>
                <xp:td>
                <xp:inputText id="input_tsnb_all"
                                disableClientSideValidation="true"
                                styleClass="doc_field_textinput" required="true" size="40" >
                <xp:this.validators>
                    <xp:validateRequired
                    message="#{javascript:return('This field is required')}">
                    </xp:validateRequired>
                </xp:this.validators>
                <xp:this.converter>
                        <xp:convertNumber pattern="0.000"></xp:convertNumber>
                </xp:this.converter>
                </xp:inputText>
                <xp:message id="message2" for="input_tsnb_all"
                                rendered="true" showDetail="false" showSummary="true"
                                style="font-style:italic;background_field-color:rgb(217,234,235);border-color:rgb(102,102,102)">
                </xp:message>
                </xp:td>
                </xp:tr>

                <xp:tr>
                <xp:td><xp:label value="build-works"/></xp:td>
                <xp:td>
                <xp:inputText type="text" size="40" id="input_tsnb_build_work"
                                disableClientSideValidation="true"
                                styleClass="doc_field_textinput" required="true">
                <xp:this.validators>
                                    <xp:validateRequired
                                        message="#{javascript:return('This field is required')}">
                                    </xp:validateRequired>
                </xp:this.validators>

                <xp:this.converter>
                    <xp:convertNumber pattern="0.000"></xp:convertNumber>
                </xp:this.converter>    

                </xp:inputText>

                    <xp:message id="message3"
                        for="input_tsnb_build_work" rendered="true" showDetail="false"
                        showSummary="true"
                        style="font-style:italic;background_field-color:rgb(217,234,235);border-color:rgb(102,102,102)">
                    </xp:message>

                </xp:td>
                </xp:tr>

                <xp:tr>
                <xp:td><xp:label value="equipment"/></xp:td>
                <xp:td>
                <xp:inputText id="input_tsnb_equipment"
                                disableClientSideValidation="true"
                                styleClass="doc_field_textinput" required="true" size="40" >
                <xp:this.validators>
                    <xp:validateRequired
                    message="#{javascript:return('This field is required')}">
                    </xp:validateRequired>
                </xp:this.validators>
                <xp:this.converter>
                        <xp:convertNumber pattern="0.000"></xp:convertNumber>
                </xp:this.converter>
                </xp:inputText>
                <xp:message id="message5" for="input_tsnb_equipment"
                                rendered="true" showDetail="false" showSummary="true"
                                style="font-style:italic;background_field-color:rgb(217,234,235);border-color:rgb(102,102,102)">
                </xp:message>
                </xp:td>
                </xp:tr>

                <xp:tr>
                <xp:td><xp:label value="other costs"/></xp:td>
                <xp:td>
                <xp:inputText type="text" size="40" id="input_tsnb_other_costs"
                                disableClientSideValidation="true"
                                styleClass="doc_field_textinput" required="true" >
                <xp:this.validators>
                    <xp:validateRequired
                        message="#{javascript:return('This field is required')}">
                    </xp:validateRequired>
                </xp:this.validators>

                <xp:this.converter>
                    <xp:convertNumber pattern="0.000"></xp:convertNumber>
                </xp:this.converter>

                </xp:inputText>

                    <xp:message id="message6"
                        for="input_tsnb_other_costs" rendered="true" showDetail="false"
                        showSummary="true"
                        style="font-style:italic;background_field-color:rgb(217,234,235);border-color:rgb(102,102,102)">
                    </xp:message>

                </xp:td>
                </xp:tr>

                <xp:tr>
                <xp:td><xp:label value="including tax"/></xp:td>
                <xp:td>
                <xp:inputText type="text" size="40" id="input_tsnb_pir"
                                disableClientSideValidation="true"
                                styleClass="doc_field_textinput" required="true">

                <xp:this.validators>
                        <xp:validateRequired
                                message="#{javascript:return('This field is required')}">
                        </xp:validateRequired>
                </xp:this.validators>

                <xp:this.converter>
                    <xp:convertNumber pattern="0.000"></xp:convertNumber>
                </xp:this.converter>                

                </xp:inputText>

                <xp:message id="message7" for="input_tsnb_pir"
                        rendered="true" showDetail="false" showSummary="true"
                        style="font-style:italic;background_field-color:rgb(217,234,235);border-color:rgb(102,102,102)">
                </xp:message>

                </xp:td>
                </xp:tr>

                <xp:tr>
                <xp:td><xp:label value="return sum"/></xp:td>
                <xp:td>

                <xp:inputText type="text" size="40"
                                id="input_tsnb_return"
                                disableClientSideValidation="true"
                                styleClass="doc_field_textinput" required="true">

                    <xp:this.validators>
                        <xp:validateRequired
                            message="#{javascript:return('This field is required')}">
                        </xp:validateRequired>
                    </xp:this.validators>

                    <xp:this.converter>
                        <xp:convertNumber pattern="0.000"></xp:convertNumber>
                    </xp:this.converter>

                </xp:inputText>

                <xp:message id="message8"
                    for="input_tsnb_return" rendered="true" showDetail="false"
                    showSummary="true"
                    style="font-style:italic;background_field-color:rgb(217,234,235);border-color:rgb(102,102,102)">
                </xp:message>

                </xp:td>
                </xp:tr>

<xp:tr>
            <xp:td colspan="2" style="padding-top: 15px">
             <xp:button id="save_part_btn" value="+Add part" style="float:right;">
             <xp:eventHandler event="onclick" submit="true"
                refreshMode="complete">
                <xp:this.action><![CDATA[#{javascript:
                            //Backend code  
}]]></xp:this.action>
             </xp:eventHandler>
             </xp:button>
            </xp:td>
            </xp:tr>
            </xp:table>
    </xp:div>

用于编辑的代码是相同的,期望使用相应的部分(后端)检索值,并且id具有前缀_edit。保存更改按钮还没有任何后端操作。

我的JQuery是:

$(document).ready(function() {
/*
Ignore it
  $('.partTableContent').hide();
  $('.expandButton').click(function() {
    // .parent() selects the A tag, .next() selects the P tag
    $(this).closest('tr').next(' tr').find('div.partTableContent').slideToggle(750);
  }); 
*/   

  var dialogAddPartDiv = $('.dialogAddPart'); 

  $('.addButton').click(function() 
  {
    dialogAddPartDiv.dialog('open');
  });

  dialogAddPartDiv.dialog(
  {
  create: function (event, ui) {


                $(".ui-corner-all").css('border-bottom-right-radius','8px');
                $(".ui-corner-all").css('border-bottom-left-radius','8px');
                $(".ui-corner-all").css('border-top-right-radius','8px');
                $(".ui-corner-all").css('border-top-left-radius','8px');

                $(".ui-dialog").css('border-bottom-left-radius','0px');
                $(".ui-dialog").css('border-bottom-right-radius','0px');
                $(".ui-dialog").css('border-top-left-radius','0px');
                $(".ui-dialog").css('border-top-right-radius','0px');

                $('.ui-dialog-titlebar-close').css('margin', '-25px -20px 0px 0px').css('border', 'solid 2px').css('border-radius', '15px').css('border-color', '#05788d');
                $('.ui-dialog-titlebar-close').css('width', '25px').css('height', '25px');
            },

    autoOpen: false,
    modal: true,
    beforeClose : function(event) 
    {
        if(!confirm("Part won't be saved. Continue"))
        {
        return false;
        }
        else 
        {

        }
    },
    width:600,
    resizable: false
  });


  var dialogEditPartDiv = $('#dialogEditPart'); 

  $('.editButton').click(function() 
  {
      dialogEditPartDiv.dialog('open');
  });

  dialogEditPartDiv.dialog(
  {
  create: function (event, ui) {

                $(".ui-corner-all").css('border-bottom-right-radius','8px');
                $(".ui-corner-all").css('border-bottom-left-radius','8px');
                $(".ui-corner-all").css('border-top-right-radius','8px');
                $(".ui-corner-all").css('border-top-left-radius','8px');

                $(".ui-dialog").css('border-bottom-left-radius','0px');
                $(".ui-dialog").css('border-bottom-right-radius','0px');
                $(".ui-dialog").css('border-top-left-radius','0px');
                $(".ui-dialog").css('border-top-right-radius','0px');

                $('.ui-dialog-titlebar-close').css('margin', '-25px -20px 0px 0px').css('border', 'solid 2px').css('border-radius', '15px').css('border-color', '#05788d');
                $('.ui-dialog-titlebar-close').css('width', '25px').css('height', '25px');
    },
    autoOpen: false,
    modal: true,
    beforeClose : function(event) 
    {
        if(!confirm("Changes won't be saved. Continue?"))
        {
        return false;
        }
        else 
        {

        }
    },
    width:600,
    resizable: false
  });

});

希望问题很清楚。我只想打开对话框,验证输入并最终执行后端代码。事实上,我希望它被隐藏起来并成为对话,而不是在页面上看到丑陋的div。感谢

1 个答案:

答案 0 :(得分:1)

你所要求的并不是一件小事,需要大量的JSF理解 - 阶段监听,部分执行,部分刷新,faces-config.xml,JavaScript等。

如果你想要实现它,你必须承受很多并继续阅读...

阶段监听器

通过faces-config.xml配置阶段侦听器。 faces-config.xml将如下所示:

<faces-config>
    <lifecycle>
        <phase-listener>demo.ValidationPhaseListener
        </phase-listener>
    </lifecycle>
    ...

在开始之前,我们首先创建一个Helper类,以便共享一个常用的方法 - 以及其他几个 - 将在以后的其他地方使用:

package demo;

public enum Helper {
    ;

    private static final String ON_SUCCESS_REFRESH_ID_PARAM = "onSuccessRefreshId";

    public static void setResponseErrorHeader(FacesContext facesContext, PhaseId phaseId) {
        HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();

        response.setHeader("Application-Error", phaseId.toString());
    }

    public static void applyOnSuccessRefreshId(FacesContext facesContext) {
        if (!AjaxUtil.isAjaxPartialRefresh(facesContext)) {
            throw new UnsupportedOperationException();
        }

        String refreshId = (String) facesContext.getExternalContext().getRequestParameterMap().get(ON_SUCCESS_REFRESH_ID_PARAM);

        if (refreshId != null) {
            ((FacesContextEx) facesContext).setPartialRefreshId(refreshId);
        }
    }

    public static void applyOnSuccessRefreshId(FacesContext facesContext, ActionEvent event) {
        if (!AjaxUtil.isAjaxPartialRefresh(facesContext)) {
            throw new UnsupportedOperationException();
        }

        Parameter param = getComponentParam(event.getComponent(), ON_SUCCESS_REFRESH_ID_PARAM);

        if (param != null) {
            ((FacesContextEx) facesContext).setPartialRefreshId(param.getValue());
        }
    }
}

验证阶段监听器类将负责设置响应标头值,我们可以在验证阶段失败时查找 。从框架的角度来看,验证错误并不对应于500错误,但始终为200.如果没有这种区别,我们就不知道是否关闭对话框。

package demo;

public class ValidationPhaseListener implements PhaseListener {

    private static final long serialVersionUID = 1L;

    @Override
    public PhaseId getPhaseId() {
        return PhaseId.PROCESS_VALIDATIONS;
    }

    @Override
    public void beforePhase(PhaseEvent phaseEvent) {

    }

    @Override
    public void afterPhase(PhaseEvent phaseEvent) {
        FacesContext facesContext = phaseEvent.getFacesContext();

        if (facesContext.getMessages().hasNext()) {
            Helper.setResponseErrorHeader(facesContext, getPhaseId());
        }
    }

}

JavaScript帮助程序库

为了鼓励重复使用和良好的组织,最好设置一个静态库,该库将加载每个使用对话框的XPage。 在这种特殊情况下,我使用bootstrap模式,因此逻辑最适合。 JS文件是这样的:

var Helper = {
    isBadRequest : function(xhr) {
        return xhr.getResponseHeader("Application-Error") !== null;
    },
    jquery : function(query) {
        if (typeof query !== "string") {
            return query;
        }

        return $(query.replace(/:/g, "\\3A"));
    },
    modal : function(id, options, additionalOptions) {
        var m = this.jquery(id);
        var addOpts = additionalOptions || {};

        if ("hide" === options) {
            var successRefreshId = m.data("success-cid");

            if (addOpts.eventId && addOpts.execId && successRefreshId) {
                XSP
                        .partialRefreshPost(
                                addOpts.refreshId || null,
                                {
                                    execId : addOpts.execId,
                                    params : {
                                        "$$xspsubmitid" : addOpts.eventId,
                                        "onSuccessRefreshId" : successRefreshId
                                    },
                                    onComplete : "if (!Helper.isBadRequest(arguments[1].xhr)) { hub.modal('"
                                            + id
                                            + "', 'hide', { hide: false }) }",
                                    onError : 'console.log(arguments[0])'
                                });

                return;
            }
        } else {
            if (addOpts.successRefreshId) {
                m.data("success-cid", addOpts.successRefreshId);
            }

            var eventId = m.data("reset-eid");

            if (eventId) {
                var componentId = m.data("reset-cid");

                addOpts.hide = function() {
                    XSP.partialRefreshPost(componentId || null, {
                        immediate : true,
                        execId : eventId,
                        params : {
                            "$$xspsubmitid" : eventId
                        }
                    });
                };
            }
        }

        for (addOpt in addOpts) {
            switch (addOpt) {
            case "show":
            case "shown":
            case "hide":
            case "hidden":
                var evName = addOpt + ".bs.modal";

                if (addOpts[addOpt] instanceof Function) {
                    m.one(evName, addOpts[addOpt]);
                } else {
                    m.off(evName);
                }

                break;
            }
        }

        m.modal(options);
    }
};

我知道,模态方法中有很多事情要做。它是复杂的,以涵盖特定的边缘情况 - 至少对我设计它的方式。你不需要过多关注它。你想知道的是,它与我在XPages一侧定义为我的模态模板的自定义控件一起工作。

模态自定义控件

模态是通过自定义控件定义的,简单&#34;简单&#34;再利用:

<xp:view xmlns:xp="http://www.ibm.com/xsp/core">

    <xp:div
        styleClass="modal inmodal ${empty compositeData.animationClass ? 'fade' : 'in'}"
        role="dialog">
        <xp:this.attrs>
            <xp:attr name="id" value="#{compositeData.clientId}" />
            <xp:attr name="data-reset-eid" value="#{compositeData.resetEventId}"
                rendered="#{not empty compositeData.resetEventId}" />
            <xp:attr name="data-reset-cid" value="#{compositeData.resetComponentId}"
                rendered="#{not empty compositeData.resetComponentId}" />
            <xp:attr name="tabindex" value="-1" />
            <xp:attr name="aria-hidden" value="true" />
        </xp:this.attrs>
        <div class="modal-dialog ${compositeData.size}">
            <div
                class="modal-content ${empty compositeData.animationClass ? '' : compositeData.animationClass}">
                <xp:div styleClass="modal-header">
                    <xp:callback facetName="header" rendered="${compositeData.headerCustom}" />

                    <xp:text rendered="${not compositeData.headerCustom}">
                        <button type="button" class="close" data-dismiss="modal">
                            <span aria-hidden="true">&#215;</span>
                            <span class="sr-only">
                                <xp:text value="${msg.app.close}" />
                            </span>
                        </button>

                        <xp:text tagName="i"
                            styleClass="fa #{compositeData.headerIcon} modal-icon" rendered="#{not empty compositeData.headerIcon}" />

                        <xp:panel tagName="h4" styleClass="modal-title"
                            rendered="#{not empty compositeData.headerTitle}">
                            <xp:text value="#{compositeData.headerTitle}" />
                        </xp:panel>

                        <xp:panel tagName="small" styleClass="font-bold"
                            rendered="#{not empty compositeData.headerDescription}">
                            <xp:text value="#{compositeData.headerDescription}" />
                        </xp:panel>
                    </xp:text>
                </xp:div>

                <div class="modal-body">
                    <xp:callback facetName="body" />
                </div>

                <xp:div styleClass="modal-footer">
                    <xp:callback facetName="footer" />
                </xp:div>
            </div>
        </div>
    </xp:div>

</xp:view>

.xsp-config定义:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
    <faces-config-extension>
        <namespace-uri>http://www.ibm.com/xsp/custom</namespace-uri>
        <default-prefix>xc</default-prefix>
    </faces-config-extension>
    <composite-component>
        <component-type>layoutModal</component-type>
        <composite-name>layoutModal</composite-name>
        <composite-file>/layoutModal.xsp</composite-file>
        <composite-extension>
            <designer-extension>
                <in-palette>true</in-palette>
            </designer-extension>
        </composite-extension>
        <property>
            <property-name>clientId</property-name>
            <property-class>string</property-class>
            <property-extension>
                <required>true</required>
            </property-extension>
        </property>
        <property>
            <property-name>size</property-name>
            <property-class>string</property-class>
            <property-extension>
                <designer-extension>
                    <editor>com.ibm.workplace.designer.property.editors.comboParameterEditor</editor>
                    <editor-parameter>modal-sm&#xd;
modal-lg</editor-parameter>
                </designer-extension>
            </property-extension>
        </property>
        <property>
            <property-name>animationClass</property-name>
            <property-class>string</property-class>
        </property>
        <property>
            <property-name>headerIcon</property-name>
            <property-class>string</property-class>
        </property>
        <property>
            <property-name>headerTitle</property-name>
            <property-class>string</property-class>
        </property>
        <property>
            <property-name>headerDescription</property-name>
            <property-class>string</property-class>
        </property>
        <property>
            <property-name>headerCustom</property-name>
            <property-class>boolean</property-class>
        </property>
        <property>
            <property-name>resetEventId</property-name>
            <property-class>string</property-class>
        </property>
        <property>
            <property-name>resetComponentId</property-name>
            <property-class>string</property-class>
        </property>
    </composite-component>
</faces-config>

除了一堆属性之外,它定义的是一系列您想要使用的模式,具体取决于模态的复杂性。如果你能够发现它我为模态定义的id是固定类型 - 而不是动态的。它不是鼓励使用固定而不是动态,但通过评估所有情况,我意识到固定id在很多情况下也有一些帮助。

链接和模态

是时候通过在页面上使用自定义控件将事物放在一起了。 让我们从链接开始。

我们使用链接&#34;准备&#34;模态。首先,使用手术精确度非常重要,以便既能提高效率,又不必担心使用模态时。 JavaScript发生在客户端,除非状态以某种方式与服务器端同步,否则服务器端不知道这一点。这一点很重要,因为除非明确告诉事件处理程序会因为操作而执行页面的完整刷新 - 这意味着整个页面会像第一次那样重建 - 至少从JavaScript的角度来看,因此失败跟踪开放式模式。

因此,无论何时您想使用模态,并且需要准备其内容,使用部分执行和部分刷新都很重要。实际上,如果你从不使用部分刷新和执行,你应该认真问自己为什么。

<xp:link id="linkOpenDialog">
    <xp:eventHandler event="onclick" submit="true"
        execMode="partial" refreshMode="partial" refreshId="modalDemoBody"
        action="#{myBean.myAction}"
        onComplete="Helper.modal('#modal-account', { backdrop: 'static', keyboard: false })" />
</xp:link>

如果你看一下上面的例子,我设置的内容读取1)execMode="partial"执行操作时忽略页面上的所有其他评估,2)refreshMode="partial" refreshId="modalDemoBody"执行操作时唯一的元素将在页面上更新的不是整个页面,而是modalDemoBody及其所有子项(即模态正文内容),3)action="#{myBean.myAction}"我的方法可能会在显示前准备我的模态, 4)onComplete="Helper.modal('#modal-account'...)"将被调用的JavaScript方法 - 它在静态库中,还记得吗? - 这实际上会激发模态。如果您不需要准备模态,则可以跳过所有这些步骤,只需将onComplete中的方法移动到链接的onclick事件(例如<xp:link id="linkOpenDialog" onclick="Helper..."

现在是页面上模态的代码。我们使用自定义组件,我们定义了我实际上不会使用的动态ID,以及我们在链接中引用的clientId。您可以定义其他可选属性,例如标题标题 - 或者您可以通过指定自定义构面完全revisit整个区域,并且在示例的情况下,resetEventId(此一个)在底部调用eventHandler并且它是帮助清除表单状态的例子,例如1)你打开模态,2)你提交了内容,3)验证失败,4)你关闭模式,从而使服务器端的表单处于不一致状态,根据您在下一页上单击的操作,可能会咬你。 (仅当保存操作未关闭模态时才会触发此操作)

然后有一个正面 - xp:key="body" - 和一个页脚 - xp:key="footer" - 来定义你的按钮。

<xc:layoutModal id="modalDemo" clientId="modal-demo"
    headerTitle="Demo" resetEventId="#{id:eventResetForm}">
    <xp:this.facets>
        <xp:panel xp:key="body" binding="#{modalDemoBody}" id="modalDemoBody">

            <!-- Here goes your content -->

        </xp:panel>
        <xp:text xp:key="footer" disableOutputTag="true">
            <button type="button" class="btn btn-white"
                data-dismiss="modal">
                <xp:text value="Close" />
            </button>
            <xp:button id="buttonSaveModal" value="Save" styleClass="btn-primary">
                <xp:eventHandler event="onclick" submit="true"
                    execMode="partial" execId="modalDemo" refreshMode="partial"
                    refreshId="modalDemoBody" actionListener="#{myBean.saveModalDemo}"
                    onComplete="if (!Helper.isBadRequest(arguments[1].xhr)) { hub.modal('#modal-demo', 'hide', { hide: false }) }">
                    <xp:this.parameters>
                        <xp:parameter name="onSuccessRefreshId"
                            value="#{id:allIsWell}" />
                    </xp:this.parameters>
                </xp:eventHandler>
            </xp:button>

            <xp:eventHandler id="eventResetForm"
                submit="false"
                action="#{javascript:myBean.resetForm(modalDemoBody)}" />
        </xp:text>
    </xp:this.facets>
</xc:layoutModal>

<xp:div id="allIsWell">

</xp:div>

在保存按钮事件处理程序中,我们仔细选择行为。我们再次使用部分执行和刷新。部分执行设置为execMode="partial" execId="modalDemo",这意味着验证将仅在页面的模态部分内发生。使用refreshMode="partial" refreshId="modalDemoBody"进行部分刷新设置,因为我们不想重新加载整个页面,从而破坏了模态状态,但它具体到足以返回表单,如果发生了可能的验证错误。

现在,而不是action param,我实际上利用了actionListener,因为它允许我发送请求附加参数(我认为无论如何都可以通过使用javascript来完成签名,例如然后传递参数)。我在这里定义的是一个id的条件行为,我想要作为动作的结果刷新,也就是说,如果验证失败刷新模态的主体,但如果成功,则刷新页面的其他一些组件(在它是<xp:div id="allIsWell">)的例子。 <xp:parameter name="onSuccessRefreshId",其名称与ON_SUCCESS_REFRESH_ID_PARAM类中的静态字符串Helper匹配。现在,如果我们的方法也没有错误地评估,那么动作中会发生的是动态更改刷新ID。如果不是,我们也会以稍后可以理解的方式使该操作无效。

public void saveModalDemo(ActionEvent event) {
    // Your logic goes here
    boolean allIsWell = false;

    if (allIsWell) {
        Helper.applyOnSuccessRefreshId(facesContext, event);
    } else {
        Helper.setResponseErrorHeader(facesContext, event.getPhaseId());
    }
}

Helper.applyOnSuccessRefreshId将读取onSuccessRefreshId参数,并使用新的参数重新路由eventHandler中定义的原始refreshId。你去了,你有条件刷新!

然后,只有这样,我们才会使用onComplete="if (!Helper.isBadRequest(arguments[1].xhr)) { hub.modal('#modal-demo', 'hide', { hide: false }) }"定义的参数来关闭对话框,这样可以确定一件事是否可以实际关闭对话框。如果它找到响应标题,表示存在错误 - 就像验证错误一样 - 它不会关闭对话框,否则它会。

我写的代码多于解释。我本应该写一篇关于它的博客文章。无论如何,通过选中this link out,您可以获得有关该流程的更多信息。然而,这里的答案是对解决问题的第一次尝试的改进。