表单事件

表单创建完成且 HTML 表单模板添加到 DOM 后, 应用程序会在表单的生命周期内触发以下表单事件:

  • on_view_form_created - 当表单已创建但尚未显示时触发此事件

  • on_view_form_shown - 当表单已显示时触发此事件

  • on_view_form_close_query - 当尝试关闭表单时触发此事件

  • on_view_form_closed - 当表单已关闭时触发此事件

  • on_view_form_keydown - 当表单发生 keydown 事件时触发此事件

  • on_view_form_keyup - 当表单发生 keyup 事件时触发此事件

对于其他表单类型 —— edit(编辑)、filter(过滤)和 param(参数), 将 “view” 替换为表单类型,例如,编辑表单的 on_edit_form_created

我们将首先解释如何使用 on_view_form_created 事件。

当用户点击菜单项时,应用程序执行 相应任务树实体项的 view 方法,该方法使用其 HTML 表单模板创建表单,并首先触发任务的 on_view_form_created 事件。

当您创建一个新项目时,任务客户端模块已包含一些代码,其中包括 on_view_form_created 事件处理程序。每次创建查看表单时都会执行此事件处理程序,并定义查看表单的默认行为。

您可以打开任务客户端模块查看此事件处理程序。 如果您需要更改项目中所有查看表单的默认行为,应在此处进行更改。

下面我们描述其主要执行步骤:

  • 初始化 view_formtable_options , 这些属性在创建查看表单和表格时被某些方法使用。

  • 根据用户权限,将默认按钮的 JQuery 事件处理程序分配给实体项的方法。 在下面的示例中,初始化了删除按钮:

    if (item.can_delete()) {
        item.view_form.find("#delete-btn").on('click.task', function(e) {
            e.preventDefault();
            item.delete_record();
        });
    }
    else {
        item.view_form.find("#delete-btn").prop("disabled", true);
    }
    
  • 执行实体组的 on_view_form_created 事件处理程序,以及实体项的 on_view_form_created 事件处理程序(如果已定义):

    if (!item.master && item.owner.on_view_form_created) {
        item.owner.on_view_form_created(item);
    }
    
    if (item.on_view_form_created) {
        item.on_view_form_created(item);
    }
    
  • 创建一个表格来显示实体项数据,并为明细表创建表格(如果已通过调用 create_view_tables 方法指定)

  • 执行 open 方法,从服务器获取实体项数据集。

  • 最后返回 true,以防止调用所有者组和实体项的 on_view_form_created 事件处理程序,因为它们已被调用(参见下面的 _process_event 方法)。

在我们初始化按钮之后、创建表格之前,我们调用了实体项本身的 on_view_form_created 事件处理程序。

例如,在演示应用程序的 tracks(曲目)实体项的客户端模块中,定义了以下 on_view_form_created 事件处理程序。 在其中,我们更改了 table_options 的 “高度(height)” 属性,创建了 “发票表格(invoice_table)” 的副本,设置其属性, 并调用其 create_table 方法来创建一个表格以显示其数据。

function on_view_form_created(item) {
  item.table_options.height -= 200;
  item.invoice_table = task.invoice_table.copy();
  item.invoice_table.paginate = false;
  item.invoice_table.create_table(item.view_form.find('.view-detail'), {
      height: 200,
      summary_fields: ['date', 'total'],
  });
  item.alert('Double-click the record in the bottom table to see track sales.');
}

该模块还有一个 on_after_scroll 事件处理程序,当用户移动到另一首曲目时将执行此处理程序,并获取该曲目的销售数据。

这个示例解释了表单事件的使用原理。

事件的触发顺序取决于事件的类型。事件生成的顺序也取决于事件的类型。

关闭查询事件

当用户尝试关闭表单时,首先会为实体项触发 on_close_query 事件(如果已定义)。

如果事件处理程序返回 true,应用程序将关闭窗体;如果事件处理程序返回 false,应用程序将保持窗体打开;否则,将以相同方式触发实体组的 on_close_query 事件(若已定义),再触发任务的 on_close_query 事件(若已定义)。

例如,默认情况下,任务客户端模块中有一个 on_edit_form_close_query 事件处理程序:

function on_edit_form_close_query(item) {
    var result = true;
    if (!item.virtual_table && item.is_changing()) {
        if (item.is_modified()) {
            item.yes_no_cancel(task.language.save_changes,
                function() {
                    item.apply_record();
                },
                function() {
                    item.cancel_edit();
                }
            );
            result = false;
        }
        else {
            item.cancel_edit();
        }
    }
    return result;
}

此代码检查记录是否已被修改,然后打开 “是/否/取消” 对话框。

如果我们想在不使用此对话框的情况下关闭表单,可以在实体项的客户端模块中定义以下 事件处理程序:

function on_edit_form_close_query(item) {
    item.cancel()
    return true;
}

Keydown、Keyup 事件

这些事件的触发方式与关闭查询事件相同,均从实体项开始;但如果事件处理程序返回 true,则不会执行组和任务的事件处理程序。

例如,默认情况下,任务客户端模块中有一个 on_edit_form_keyup 事件处理程序:

function on_edit_form_keyup(item, event) {
    if (event.keyCode === 13 && event.ctrlKey === true){
        item.edit_form.find("#ok-btn").focus();
        item.apply_record();
    }
}

此代码在用户按下 Ctrl+Enter 时将记录的更改保存到数据库表。

假设我们希望在用户按下 Enter 时保存更改。那么我们在实体项客户端模块中编写以下事件处理程序:

function on_edit_form_keyup(item, event) {
    if (event.keyCode === 13){
        item.edit_form.find("#ok-btn").focus();
        item.apply_record();
        return true;
    }
}

在这种情况下,当用户按下 Enter 时,任务的事件处理程序将不会被调用。

所有其他事件

对于其他事件,首先调用任务的事件处理程序;如果任务的事件处理程序没有返回 true,则执行组的事件处理程序;如果组的事件处理程序没有返回 true,再调用实体项的事件处理程序。

此机制由 jam.js 模块中 Item 类的 _process_event 方法实现。

_process_event: function(form_type, event_type, e) {
  var event = 'on_' + form_type + '_form_' + event_type,
      can_close;
  if (event_type === 'close_query') {
      if (this[event]) {
          can_close = this[event].call(this, this);
      }
      if (!this.master && can_close === undefined && this.owner[event]) {
          can_close = this.owner[event].call(this, this);
      }
      if (can_close === undefined && this.task[event]) {
          can_close = this.task[event].call(this, this);
      }
      return can_close;
  }
  else if (event_type === 'keyup' || event_type === 'keydown') {
      if (this[event]) {
          if (this[event].call(this, this, e)) return;
      }
      if (!this.master && this.owner[event]) {
          if (this.owner[event].call(this, this, e)) return;
      }
      if (this.task[event]) {
          if (this.task[event].call(this, this, e)) return;
      }
  }
  else {
      if (this.task[event]) {
          if (this.task[event].call(this, this)) return;
      }
      if (!this.master && this.owner[event]) {
          if (this.owner[event].call(this, this)) return;
      }
      if (this[event]) {
          if (this[event].call(this, this)) return;
      }
  }
}