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

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

1. JQuery ID的选择器

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

   

使用类似这个var dialog = $('#addingDialog')的JQuery选择器 – 它会给我们没有结果,因为var dialog = $('#addingDialog') id是动态计算的。 所以我决定像这样使用类(styleClasses,如果你愿意)声明它

   

JQuery是这样的: var dialog = $('.addingDialog') 。 似乎工作,虽然不好。

2.单击应该validation它的按钮并使所有后端的东西不起作用:(

不幸的是,当我单击“添加”按钮(保存的按钮)时没有任何反应 – 即使validation失败并且没有保存任何内容,对话框也会关闭,即使输入正确也是如此。

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

但这不是正确的解决方案,至少不适用于这种情况。 但即便在这里出现另一个问题 – validation

有两个对话框:一个用于添加,另一个用于编辑(JQuery不允许只有一个具有不同按钮function的对话框),两个都有validation,我必须输入一些东西进行编辑才能添加新的! 最初我认为XPage中的validation工作原理是这样的 – 当用户点击相应的div检查中的所有inputText的 相应按钮(添加或编辑)时,如果它是正确的 – validation成功并且后端操作发生。 问题是 – 我怎样才能让它像这样工作? 事实certificate, 页面上的每个inputText都会检查 。 我不希望它像这样工作(截图不使用JQuery) 这是我在页面上看到的 。 如果我在编辑对话框中输入任何值并单击“+添加零件”,一切正常。 也许正是因为这个对话框中的saving actions不会发生? 因为我只打开了一个对话框,但validation“看到”其他隐藏的输入是空的,因此validation失败了? 这是我的代码

                                                                                                                            

编辑的代码是相同的,期望使用相应的部分(后端)检索值,并且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 }); }); 

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

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

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

阶段监听器

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

   demo.ValidationPhaseListener   ... 

在开始之前,我们首先创建一个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()); } } } 

validation阶段监听器类将负责设置响应标头值,以便在validation阶段失败时查找。 从框架的角度来看,validation错误不对应于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方面定义为我的模态模板的自定义控件一起工作。

模态自定义控件

模态通过自定义控件定义,以便“轻松”重复使用:

             

它的.xsp-config定义:

    http://www.ibm.com/xsp/custom xc   layoutModal layoutModal /layoutModal.xsp   true    clientId string  true    size string   com.ibm.workplace.designer.property.editors.comboParameterEditor modal-sm
 modal-lg     animationClass string   headerIcon string   headerTitle string   headerDescription string   headerCustom boolean   resetEventId string   resetComponentId string    

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

链接和模态

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

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

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

    

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

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

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

                     

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

现在,我实际上利用了actionListener ,而不是action参数,因为它允许我使用请求发送其他参数(我认为无论如何都可以通过使用javascript签名,然后在那里传递参数)来完成。 我在这里定义的是一个条件行为,因为我想要刷新作为动作的结果,也就是说,如果validation失败刷新模态的主体,但如果成功,则刷新页面的其他一些组件(在这个例子是 )。 ,其名称与Helper类中的静态字符串ON_SUCCESS_REFRESH_ID_PARAM匹配。 现在,如果我们的方法也可以无错误地评估,那么动作中会发生的是动态更改刷新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 }) }"定义的参数,它确定一件事,是否可以实际关闭对话框。 如果它发现响应头表示存在错误 - 就像validation错误一样 - 它将不会关闭对话框,否则它将会关闭。

我写的代码多于解释。 我本应该写一篇关于它的博客文章。 无论如何,通过查看此链接,您可能会获得有关该过程的更多信息。 然而,这里的答案是对解决问题的第一次尝试的改进。