尝试在 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 的论坛回复,其中描述了使用带有计时器的技术来触发常规文档保存...

https://www-10.lotus.com/ldd/xpagesforum.nsf/xpTopicThread.xsp?documentId=B5ECAEC50241A3EE85257B32008248FC

我已经在我的 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 秒将:

  1. 在 Domino 控制台上打印一些文本,向您展示事件是在服务器端计算的
  2. 用戳记和执行日期填写字段
  3. 在浏览器控制台打印方法执行的时间 运行

没有额外的依赖项或片段。它开箱即用。