ExtJS 更改事件侦听器未能触发

Posted

技术标签:

【中文标题】ExtJS 更改事件侦听器未能触发【英文标题】:ExtJS Change Event Listener failing to fire 【发布时间】:2009-12-02 14:45:52 【问题描述】:

http://twitter.com/jonathanjulian 要求我将这个问题作为一个问题发布到 *** 上,然后被其他几个人转发。我已经有一个丑陋的解决方案,但正在按要求发布原始问题。

所以这是背景故事。我们有一个庞大的数据库应用程序,它专门为客户端视图使用 ExtJS。我们正在为从远程存储加载的行视图使用 GridPanel (Ext.grid.GridPanel)。

在我们的每个界面中,我们还有一个 FormPanel (Ext.form.FormPanel) 显示允许用户从 GridPanel 创建或编辑记录的表单。 GridPanel 列绑定到 FormPanel 表单元素,因此当在 GridPanel 中选择记录时,所有值都会填充到表单中。

在每个表单上,我们都有一个表行 ID(主键)的输入字段,其定义如下:

var editFormFields = [

     fieldLabel: 'ID',
     id: 'id_field',
     name: 'id',
     width: 100,
     readOnly: true, // the user cannot change the ID, ever.
     monitorValid: true
 /* other fields removed */
];

所以,这一切都很好。这适用于我们所有的应用程序。在构建新界面时,要求我们需要使用第三方文件存储 API,该 API 以加载在 IFrame 中的小网页形式提供界面。

我将 IFrame 代码放在了 FormPanel 的 html 参数中:

var editForm = new Ext.form.FormPanel(
   html: '<div style="width:400px;"><iframe id="upload_iframe" src="no_upload.html"  ></iframe></div>',
   /* bunch of other parameters stripped for brevity */
);

所以,每当用户选择一条记录时,我需要将 IFrame 的 src 属性更改为我们正在使用的服务的 API URL。类似于http://uploadsite.com/upload?appname=whatever&id=$id_of_record_selected

我最初进入 id 字段(粘贴在上面)并添加了一个更改侦听器。

var editFormFields = [

     fieldLabel: 'ID',
     id: 'id_field',
     name: 'id',
     width: 100,
     readOnly: true, // the user cannot change the ID, ever.
     monitorValid: true,
     listeners: 
        change: function(f,new_val) 
           alert(new_val);
        
     
 /* other fields removed */
];

很好很简单,只是它只在用户专注于该表单元素时才有效。其余时间它根本没有开火。

对我已经过了最后期限而只需要它工作感到沮丧,我迅速实施了一个衰减轮询器来检查值。这是一个可怕的,丑陋的黑客。但它按预期工作。

我会在这个问题的答案中粘贴我丑陋的肮脏技巧。

【问题讨论】:

这是什么 ExtJS 版本? 2009 年发布的任何版本。:) 很久以前了。 【参考方案1】:

"GridPanel 列绑定到 FormPanel 表单元素,以便 当一条记录被选中时 GridPanel,所有的值都是 填写在表单中。”

正如我从上面的引用中了解到的那样,rowclick 事件实际上是首先触发表单更改的原因。为避免轮询,这可能是监听的地方,并最终引发您的自定义更改事件。

【讨论】:

谢谢。这完美地工作。现在,如果我能自己在 ext 文档中找到它就好了。 :D 我将你标记为正确答案。 仅供参考,通常最好绑定到 SelectionModel 的更改事件而不是网格的单击事件。这样键盘导航将触发相同的处理程序。 很高兴你得到了答案,埃里克!【参考方案2】:

这是我为解决这个问题所做的丑陋的黑客攻击:

var current_id_value = '';
var check_changes = function(offset) 
   offset = offset || 100;
   var id_value = document.getElementById('id_field').value || '';
   if ( id_value && ( id_value != current_id_value ) ) 
      current_id_value = id_value;
      change_iframe(id_value);
    else 
      offset = offset + 50;
      if ( offset > 2500 ) 
         offset = 2500;
       
      setTimeout(function()  check_changes(offset); , offset);
   
;

var change_iframe = function(id_value) 
   if ( id_value ) 
      document.getElementById('upload_iframe').src = 'http://api/upload.php?id=' + id_value;
    else 
      document.getElementById('upload_iframe').src = 'no_upload.html';
      

   setTimeout(function()  check_changes(100); , 1500);
;

它不漂亮,但它有效。所有的老板都很高兴。

【讨论】:

【参考方案3】:

如果您花一点时间阅读源代码,您会看到 Ext.form.Field 类仅在 onBlur 函数中触发该更改事件

【讨论】:

我阅读了源代码。我知道它为什么这样做。我只是原则上不同意这一点。我不应该求助于丑陋的黑客来获取表单字段中已更改的值。作为一个严肃的现代框架,应该有一些机制让我能够捕获这些信息。我担心(以及最初发布推文的原因)是我所做的 99% 的工作都能很快完成,为此我很感激。剩下的 1% 花费(平均(作为一个疯狂的猜测))我的时间多 1000%。 您可以使用 keyup/keydown/keypress(将 enableKeyEvents 设置为 true)侦听器然后检查值吗?可能比轮询选项略好。 这是个好主意,但不能保证用户会按下某个键。我们可能能够保证用户至少会触发一个点击事件,尽管我必须在正文级别捕获它以获取每个可能的点击场景。这是一个好主意(鼠标事件),我可能会尝试。好主意。 这样做是因为 W3C 是这样定义更改事件的。 “当控件失去输入焦点并且在获得焦点后其值已被修改时,会发生更改事件。此事件对 INPUT、SELECT 和 TEXTAREA 元素有效。” (w3.org/TR/DOM-Level-2-Events/events.html) 另外,关于“多出 1000% 的时间”的评论——难道没有任何框架可以这么说吗?您是否曾经使用过能够 100% 解决编码问题的框架?如果是这样,请给我它的链接;)

以上是关于ExtJS 更改事件侦听器未能触发的主要内容,如果未能解决你的问题,请参考以下文章

Ext.js 2 复选框和事件通过更改侦听器触发两次

ExtJS5 ViewController 侦听器未触发

Ext JS 3.4:用于单元格编辑的事件监听器

在焦点侦听器中更改复合可绘制时,EditText会无限地触发焦点更改事件

更改侦听器在 extjs 中不起作用

甚至从事件侦听器/ ExtJS 禁用组合框中的项目