【问题标题】:XPages event code executing twice rather then onceXPages 事件代码执行两次而不是一次
【发布时间】:2013-10-30 17:08:45
【问题描述】:

这是我想做的:

在 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>

感谢任何信息。非常感谢!!!

【问题讨论】:

    标签: xpages


    【解决方案1】:

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

    你需要做什么来阻止回车键使用 event.preventDefaults() 调用提交表单。这是更新后的 CSJS

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

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

    【讨论】:

    • 另一种非常简单的方法是在表单的某处放置一个 style="display:none" 的输入字段:-)
    【解决方案2】:

    大卫,

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

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

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

    【讨论】:

      【解决方案3】:

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

      为什么甚至需要 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”事件)

      【讨论】:

        猜你喜欢
        • 2011-12-08
        • 2023-01-13
        • 2017-07-07
        • 1970-01-01
        • 2018-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多