2

这是我想要做的:

在 XPage 上,我想要一个编辑框控件,当用户按下回车键时,它会调用一些服务器端代码(Java bean 或 SSJS)。主要用例是此页面将从 iPad 运行并附加蓝牙条形码扫描仪。该扫描仪模拟键盘。用户将点击编辑框。然后他们将使用扫描仪进行扫描,条形码将与“输入”键一起输入。下次扫描需要立即清除编辑框,并需要处理扫描的值。该处理将对 java bean 做各种后端事情,然后返回一条消息以显示在页面上。基本上是其中之一:1. 未找到项目,2. 项目可用并已分配,3. 项目已分配但您仍然可以拥有它 4. 项目不可用

我有这方面的代码,总体而言核心代码运行良好。我通常使用 onchange 事件,但由于我遇到了这个问题,我转向了 onkeypress 事件。这也是让它在 IE 中运行的一次尝试。同样,目标仅适用于 iPad/Safari,但我希望它也能在桌面浏览器上运行。我目前仅使用 Chome 进行测试。

在编辑框的 CSJS 部分中,我有以下代码:

var e = dojo.fixEvent(thisEvent);
if (e.keyCode == dojo.keys.ENTER) {
return true;
} else {
return false;
}

我的想法是我只想在 Enter 上调用 SSJS。

这是清除编辑框、处理值然后设置几个 viewScope 变量的 SSJS 代码。

// Get the value off the page and put it in to the key variable
var key:String = getComponent("scanBox").getValue();
// clear the scanbox so it's ready for the next scan.
getComponent("scanBox").setValue("");
//Managed Bean to hold the last scan value - since the scanbox is cleared we do want to show the value
Scan.setLastScan(key);

// Managed Bean to process the item.
AddToJob.processItem(key);

viewScope.put("vsShowAssignPanel", true);
viewScope.put("vsShowMessagePanel", false);

SSJS 代码设置为部分更新页面的主要内容。我正在使用引导程序,并试图刷新页面上的所有内容,除了顶部和底部导航栏。编辑框本身位于部分刷新区域中,因为我在扫描后清除了值。

最后,问题来了:

按钮的 SSJS 代码正在运行两次。不是全部出于某种原因,但可能是 90% 的时间。我没有点击两次。我测试的方法是在我的桌面上使用 Chrome,我将一个值粘贴到该字段中,然后在键盘上按一次 Enter。

如果我正在尝试扫描并分配带有条形码的项目。它首先运行良好。它更新对象并将字段保存到后端 NotesDocument 以将其标记为已分配。只想要我想要的。但是第二次通过点击,它阻止了该项目已经分配并给我回了错误的信息。

经过大量试验和错误后,我相当肯定 JSF 生命周期中的某些东西导致它运行两次。为什么我不知道。我不知道如何得到它一次。

到目前为止,我发现的唯一好的解决方法是“AddToJob.processItem”方法。“AddToJob”是 viewScope 中的托管 bean。在那里我存储并保留最后一个条形码。然后我检查一下值是否相同。如果是这样,那么我假设它在第二次运行并停止处理。

多年来,我一直在编辑控件的 on change 事件中使用调用代码的基本概念。但那是在 XPages Mobile Controls 内部,有时那里的行为确实有点不同。我正在尝试重新编写此应用程序以使用 Bootstrap 而不是 XPages Mobile 控件。

如果有帮助,下面是编辑控件的完整 XML 标记。

<xp:inputText id="scanBox" styleClass="newTarget">
<xp:this.attrs>
    <xp:attr name="placeholder" value="Tap to Scan..." />
    <xp:attr name="autocorrect" value="off" />
</xp:this.attrs>
<xp:this.dojoAttributes>
    <xp:dojoAttribute name="autocorrect" value="off" />
</xp:this.dojoAttributes>
<xp:eventHandler event="onkeypress" submit="true" refreshMode="partial" refreshId="mainPanel">
<xp:this.script><![CDATA[var e = dojo.fixEvent(thisEvent);
if (e.keyCode == dojo.keys.ENTER) {
return true;
} else {
return false;
}]]></xp:this.script>
<xp:this.action><![CDATA[#{javascript:// Get the value off the page and put it in to the key variable
var key:String = getComponent("scanBox").getValue();
// clear the scanbox so it's ready for the next scan.
getComponent("scanBox").setValue("");

//Managed Bean to hold the last scan value - since the scanbox is cleared we do want to show the value
Scan.setLastScan(key);

// Managed Bean to process the item.
AddToJob.processItem(key);

viewScope.put("vsShowAssignPanel", true);
viewScope.put("vsShowMessagePanel", false);}]]></xp:this.action>
</xp:eventHandler></xp:inputText>

任何信息表示赞赏。非常感谢!!!

4

3 回答 3

7

Enter 键是一个特殊的键,因为按 Enter 键也可以提交您当前所在的表单。在这种情况下,您实际上有两个 POST 请求访问服务器,一个用于部分请求,另一个用于提交表单时。

您需要做的是防止 enter 键使用 event.preventDefaults() 调用提交表单。这是更新的 CSJS

var e = dojo.fixEvent(thisEvent);
if (e.keyCode == dojo.keys.ENTER) {
    e.preventDefault();
    return true;
} else {
    return false;
}

现在表单不会被提交,但部分刷新会正确触发。

于 2013-10-30T19:48:20.083 回答
0

如果我在这里遗漏了什么,请原谅我,但在我看来,你已经建立了一个不必要的复杂设计。

为什么甚至需要 CSJS 或 SSJS?

意思是,您是否尝试过一些简单的标记和一个 bean 来进行处理?

示例标记:

<xp:panel
id="panelbarcode">
<xp:inputText
    id="barcode1"
    value="#{MyBean.barcode}">
    <xp:eventHandler
        event="onchange"
        submit="true"
        refreshMode="partial"
        refreshId="panelbarcode" />
</xp:inputText>
</xp:panel>

示例 Bean 代码:

public class MyBean implements Serializable {

private static final long serialVersionUID = 8541L;

// Zero-Argument Constructor
public MyBean() {}

public String getBarcode() {
    // give out a barcode here, 
    // or return "" for an empty barcode
    return "";
} 

public void setBarCode(String barcode) { 
    // process the scanned in barcode 
} 
}

(编辑以摆脱愚蠢的“onClick”事件)

于 2013-10-30T17:32:38.023 回答
0

大卫,

不是真正的特定 XPages 解决方案,但我必须在 Notes 客户端中执行此操作 - 在其中扫描条形码 - 对其进行处理,然后清除该字段,然后可以扫描下一个。操作员不在客户端(它是一个蓝牙扫描仪)。

我承认我的解决方案有点讨厌,那就是使用 NotesTimer - 检查字段内容以查看它是否为空或是否具有与以前相同的值。为了确保我没有捕捉到部分扫描,我做了两次检查,如果值没有改变,那么我处理了它。

那么毕竟 - 你不能使用 Javascript 计时器并遵循相同的逻辑吗?

于 2013-10-30T17:56:22.943 回答