尝试在 XPage 上使用 'executeOnServer' 从 Javascript 触发 SSJS
Trying to trigger SSJS from Javascript using 'executeOnServer' on an XPage
我有一个相当长的选项卡式 XPage 表单供访问者填写,我想每隔几分钟在后端自动保存一次。
整个表单代表一个托管 bean,我可以 populate/save 使用按钮手动从 bean 值生成 Domino 文档,只需调用...
portfolio.save(sessionScope.unid,false)
我找到了杰里米·霍奇 (Jeremy Hodge) 的优秀 post(伟大的旧技巧如何经得起时间的考验!),它解释了该技术...
http://xpages.info/XPagesHome.nsf/Entry.xsp?documentId=88065536729EA065852578CB0066ADEC
然后我发现了来自 Paul Calhoun 的论坛回复,其中描述了使用带有计时器的技术来触发常规文档保存...
我已经在我的 XPage 上实现了该技术,但 SSJS 根本没有触发。
我什至放置了 'onStart' 和 'onComplete' 事件来验证一切是否按预期工作。计数器工作,控制台显示计时器,警报每 5 秒左右出现一次......但 SSJS 根本没有启动。
完成工作的我的事件处理程序...
<xp:eventHandler event="onfubar" id="autoSave" submit="false">
<xp:this.action><![CDATA[#{javascript:portfolio.save(sessionScope.unid,false);}]]>
</xp:this.action>
</xp:eventHandler>
... 以及触发常规保存的事件处理程序(是的,我知道我已经删除了 'executeOnServer' 命令并手动添加了其他参数 - 只是试图隔离问题)。 .
<xp:eventHandler event="onClientLoad" submit="false">
<xp:this.script><![CDATA[
var executeOnServer = function () {
// must supply event handler id or we're outta here....
if (!arguments[0])
return false;
// the ID of the event handler we want to execute
var functionName = arguments[0];
// OPTIONAL - The Client Side ID that you want to partial refresh after executing the event handler
var refreshId = (arguments[1]) ? arguments[1] : "@none";
var form = (arguments[1]) ? XSP.findForm(arguments[1]) : dojo.query('form')[0];
// OPTIONAL - Options object contianing onStart, onComplete and onError functions for the call to the
// handler and subsequent partial refresh
var options = (arguments[2]) ? arguments[2] : {};
// Set the ID in $$xspsubmitid of the event handler to execute
dojo.query('[name="$$xspsubmitid"]')[0].value = form.id + ':' + functionName;
XSP._partialRefresh("post", form, refreshId, options);
}
var x = 0;
var form = document.forms[0];
t = new dojox.timing.Timer(3600);
t.onTick = function() {
x+=1;
console.info(x);
if(x > 4){
x = 0;
console.info("reset");
executeOnServer('autoSave','@none',{
onStart: function() { alert('starting!'); },
onComplete: function() { alert('complete!'); },
onError: function() { alert('DANGER WILL ROBINSON!'); }
});
}
}
t.onStart = function() {
console.info("Starting timer");
}
t.start();]]></xp:this.script>
</xp:eventHandler>
我知道我一定是漏掉了什么,我可能正盯着它看,但我就是想不出我哪里做错了。
非常感谢您对问题的任何见解(以及正确方向的观点!)。
Terry,提示一下,您是否查看浏览器控制台以查看是否抛出任何错误(来自客户端代码)?您是否启用了错误日志记录以查看是否在您的 SSJS/Java 代码中抛出了错误?
确保您引用了正确的 ID。这是一个简单的工作示例(没有 executeOnServer 函数和您的计时器逻辑)。代码在页面加载完成后运行:
<xp:scriptBlock id="scriptBlockAutoSave">
<xp:this.value><![CDATA[
XSP.addOnLoad(function(){
executeOnServer('#{javascript:getComponent('autoSave').getClientId(facesContext)}');
});
]]></xp:this.value>
</xp:scriptBlock>
它实际上可以比您找到的片段更简单(您可以放弃所有片段)...
考虑以下 bean:
public class PortfolioBean implements Serializable {
private static final long serialVersionUID = 1L;
private Map<String, Object> data = new HashMap<String, Object>();
public Map<String, Object> getData() {
return data;
}
public void autoSave(String unid, Boolean something) {
System.out.println("The unid is " + unid + " and something is " + something);
data.put("stamp", "autosave at " + new Date());
}
}
以及以下 xsp 源代码:
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:div id="myForm" style="padding: 20px;">
<xp:eventHandler event="onautosave" id="eventAutoSave"
submit="false" action="#{javascript:portfolio.autoSave(sessionScope.unid, false)}" />
<p>Stamp</p>
<xp:inputText id="inputStamp" value="#{portfolio.data.stamp}" size="60" />
</xp:div>
<xp:scriptBlock value="
XSP.addOnLoad(function() {
window.setInterval(function() {
XSP.partialRefreshPost('#{id:inputStamp}', {
execId: '#{id:myForm}',
params: { '$$xspsubmitid' : '#{id:eventAutoSave}' },
onComplete: function() { console.log('complete at ' + new Date()); }
});
}, 5000);
});" />
</xp:view>
我创建了一个 myForm
容器来创建一个 "anchor" 并缩小页面中被评估、阅读提交或执行的部分(考虑到最佳性能的最佳实践)。 myForm
因此是执行 ID。 执行 ID 属于包含您要触发的事件处理程序的元素,这一点很重要。例如,如果我将 onautosave
事件放在 myForm
div 之外,则不会触发该事件。如果你不在乎(糟糕!)你可以删除 execId: '#{id:myForm}'
属性 传递给 XSP.partialRefreshPost
方法调用中的对象,此时,无论xsp组件排列。
此外,使用 XSP.partialRefreshPost
您可以决定是否要部分刷新页面的任何元素。我放了 #{id:inputStamp}
这样您就可以看到输入字段中填满了触发自动保存后产生的文本。如果您知道您不必显示服务器端方法评估产生的任何 DOM 更改,您可以指定一个空字符串(如 XSP.partialRefreshPost('',
),这意味着 norefresh
在客户端。但是您仍然可以在操作完成时使用 onComplete
属性 做一些事情,正如您从示例中看到的那样。
在 params
属性 中有一个带有 属性 的附加对象,它定义了您要触发的操作的 ID:{ '$$xspsubmitid' : '#{id:eventAutoSave}' }
.
总之,以上代码每 5 秒将:
- 在 Domino 控制台上打印一些文本,向您展示事件是在服务器端计算的
- 用戳记和执行日期填写字段
- 在浏览器控制台打印方法执行的时间 运行
没有额外的依赖项或片段。它开箱即用。
我有一个相当长的选项卡式 XPage 表单供访问者填写,我想每隔几分钟在后端自动保存一次。
整个表单代表一个托管 bean,我可以 populate/save 使用按钮手动从 bean 值生成 Domino 文档,只需调用...
portfolio.save(sessionScope.unid,false)
我找到了杰里米·霍奇 (Jeremy Hodge) 的优秀 post(伟大的旧技巧如何经得起时间的考验!),它解释了该技术...
http://xpages.info/XPagesHome.nsf/Entry.xsp?documentId=88065536729EA065852578CB0066ADEC
然后我发现了来自 Paul Calhoun 的论坛回复,其中描述了使用带有计时器的技术来触发常规文档保存...
我已经在我的 XPage 上实现了该技术,但 SSJS 根本没有触发。 我什至放置了 'onStart' 和 'onComplete' 事件来验证一切是否按预期工作。计数器工作,控制台显示计时器,警报每 5 秒左右出现一次......但 SSJS 根本没有启动。
完成工作的我的事件处理程序...
<xp:eventHandler event="onfubar" id="autoSave" submit="false">
<xp:this.action><![CDATA[#{javascript:portfolio.save(sessionScope.unid,false);}]]>
</xp:this.action>
</xp:eventHandler>
... 以及触发常规保存的事件处理程序(是的,我知道我已经删除了 'executeOnServer' 命令并手动添加了其他参数 - 只是试图隔离问题)。 .
<xp:eventHandler event="onClientLoad" submit="false">
<xp:this.script><![CDATA[
var executeOnServer = function () {
// must supply event handler id or we're outta here....
if (!arguments[0])
return false;
// the ID of the event handler we want to execute
var functionName = arguments[0];
// OPTIONAL - The Client Side ID that you want to partial refresh after executing the event handler
var refreshId = (arguments[1]) ? arguments[1] : "@none";
var form = (arguments[1]) ? XSP.findForm(arguments[1]) : dojo.query('form')[0];
// OPTIONAL - Options object contianing onStart, onComplete and onError functions for the call to the
// handler and subsequent partial refresh
var options = (arguments[2]) ? arguments[2] : {};
// Set the ID in $$xspsubmitid of the event handler to execute
dojo.query('[name="$$xspsubmitid"]')[0].value = form.id + ':' + functionName;
XSP._partialRefresh("post", form, refreshId, options);
}
var x = 0;
var form = document.forms[0];
t = new dojox.timing.Timer(3600);
t.onTick = function() {
x+=1;
console.info(x);
if(x > 4){
x = 0;
console.info("reset");
executeOnServer('autoSave','@none',{
onStart: function() { alert('starting!'); },
onComplete: function() { alert('complete!'); },
onError: function() { alert('DANGER WILL ROBINSON!'); }
});
}
}
t.onStart = function() {
console.info("Starting timer");
}
t.start();]]></xp:this.script>
</xp:eventHandler>
我知道我一定是漏掉了什么,我可能正盯着它看,但我就是想不出我哪里做错了。
非常感谢您对问题的任何见解(以及正确方向的观点!)。
Terry,提示一下,您是否查看浏览器控制台以查看是否抛出任何错误(来自客户端代码)?您是否启用了错误日志记录以查看是否在您的 SSJS/Java 代码中抛出了错误?
确保您引用了正确的 ID。这是一个简单的工作示例(没有 executeOnServer 函数和您的计时器逻辑)。代码在页面加载完成后运行:
<xp:scriptBlock id="scriptBlockAutoSave">
<xp:this.value><![CDATA[
XSP.addOnLoad(function(){
executeOnServer('#{javascript:getComponent('autoSave').getClientId(facesContext)}');
});
]]></xp:this.value>
</xp:scriptBlock>
它实际上可以比您找到的片段更简单(您可以放弃所有片段)... 考虑以下 bean:
public class PortfolioBean implements Serializable {
private static final long serialVersionUID = 1L;
private Map<String, Object> data = new HashMap<String, Object>();
public Map<String, Object> getData() {
return data;
}
public void autoSave(String unid, Boolean something) {
System.out.println("The unid is " + unid + " and something is " + something);
data.put("stamp", "autosave at " + new Date());
}
}
以及以下 xsp 源代码:
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:div id="myForm" style="padding: 20px;">
<xp:eventHandler event="onautosave" id="eventAutoSave"
submit="false" action="#{javascript:portfolio.autoSave(sessionScope.unid, false)}" />
<p>Stamp</p>
<xp:inputText id="inputStamp" value="#{portfolio.data.stamp}" size="60" />
</xp:div>
<xp:scriptBlock value="
XSP.addOnLoad(function() {
window.setInterval(function() {
XSP.partialRefreshPost('#{id:inputStamp}', {
execId: '#{id:myForm}',
params: { '$$xspsubmitid' : '#{id:eventAutoSave}' },
onComplete: function() { console.log('complete at ' + new Date()); }
});
}, 5000);
});" />
</xp:view>
我创建了一个 myForm
容器来创建一个 "anchor" 并缩小页面中被评估、阅读提交或执行的部分(考虑到最佳性能的最佳实践)。 myForm
因此是执行 ID。 执行 ID 属于包含您要触发的事件处理程序的元素,这一点很重要。例如,如果我将 onautosave
事件放在 myForm
div 之外,则不会触发该事件。如果你不在乎(糟糕!)你可以删除 execId: '#{id:myForm}'
属性 传递给 XSP.partialRefreshPost
方法调用中的对象,此时,无论xsp组件排列。
此外,使用 XSP.partialRefreshPost
您可以决定是否要部分刷新页面的任何元素。我放了 #{id:inputStamp}
这样您就可以看到输入字段中填满了触发自动保存后产生的文本。如果您知道您不必显示服务器端方法评估产生的任何 DOM 更改,您可以指定一个空字符串(如 XSP.partialRefreshPost('',
),这意味着 norefresh
在客户端。但是您仍然可以在操作完成时使用 onComplete
属性 做一些事情,正如您从示例中看到的那样。
在 params
属性 中有一个带有 属性 的附加对象,它定义了您要触发的操作的 ID:{ '$$xspsubmitid' : '#{id:eventAutoSave}' }
.
总之,以上代码每 5 秒将:
- 在 Domino 控制台上打印一些文本,向您展示事件是在服务器端计算的
- 用戳记和执行日期填写字段
- 在浏览器控制台打印方法执行的时间 运行
没有额外的依赖项或片段。它开箱即用。