表单

表单面板 不过是一个基本的添加表单的 面板. 只要有从用户那里收集数据的Ext 应用程序 就有表单面板的使用.

除此之外, 表单面板可以使用任何 容器布局, 提供一种灵活便捷的方式处理字段显示的位置. 表单面板还可以被绑定到 模型, 使得很容易从服务器加载或提交数据.

Form Panel之下封装着一个处理所有的输入, 验证, 提交, 和从服务器加载数据的Basic Form . 这意味着许多Basic Form的配置选项可以直接应用于Form Panel上.

Basic Form

开始之前,看一个如何创建一个简单收集用户数据的表单例子:

编辑 预览 在Fiddle打开
Ext.create('Ext.form.Panel', {
    renderTo: document.body,
    title: 'User Form',
    height: 150,
    width: 300,
    bodyPadding: 10,
    defaultType: 'textfield',
    items: [
        {
            fieldLabel: 'First Name',
            name: 'firstName'
        },
        {
            fieldLabel: 'Last Name',
            name: 'lastName'
        },
        {
            xtype: 'datefield',
            fieldLabel: 'Date of Birth',
            name: 'birthDate'
        }
    ]
});

这个表单呈现有三个字段 - “First Name”, “Last Name”, 和 “Date of Birth”. 使用items 配置项把字段都添加到表单面板里.

fieldLabel 配置项定义了字段旁边的标签显示文本, 以及name 配置项变成了基本的HTML字段的name 属性.

请注意Form Panel有一个defaultType(缺省类型)‘textfield’.这意味着任何没有指定xtype(例子中的 “First Name” 和 “Last Name” 字段)的项, 都是 Text Field(文本输入控件).

反之,“Date of Birth” 字段,xtype明确的被配置成‘datefield’, 使得它是一个Date Field(日期字段). 日期字段(Date Fields)期望只包含有效的日期数据和选择日期的DatePicker(日期选择器).

Fields(字段)

Field Types(字段类型)

Ext JS 提供了一组标准的字段类型. 任何在Ext.form.field 命名空间下的字段都可以在Form Panel(表单面板)中使用. 更多信息请看每一种Field(字段)类型的API文档:

验证

1. 内置验证

Ext JS 内置了支持任何类型的Field(字段)的验证,并且有些Fields(字段)内置了验证规则.

例如, 如果在Date Field输入了一个不能被转换为Date的值, 这个Field(字段)的HEML元素将会被添加一个x-form-invalid-field CSS样式.

如果有必要, 这个CSS样式可以通过invalidCls 配置项修改.补充的invalidCls给输入(Field)字段添加了一个红色的边框(以及一条红色的无效下划线(“invalid underline”)标识当使用经典主题):

Invalid Field

当一个Field(字段)包含无效的数据时,它将展现一个错误的消息. 默认情况下,错误消息会以提示信息的方式展现:

Invalid Field Hover

通过msgTarget 配置项可以很容易的更改Field’s(字段的)错误信息展现的位置, 以及invalidText 配置项可以改变错误消息.

每一个字段(Field)都提供了自己的invalidText实现, 并且许多都支持在错误消息中标识替换(token replacement).

例如, 在Date Field’s(日期输入控件的) invalidText里, 任何出现“{0}”的地方都将被替换成输入框的值, 任何 出现“{1}”的地方都将被替换成要求的日期格式format.

下面的代码示范如何直接向错误消息直接放置在Field(控件)下面, 并且自定义错误消息文本:

{
    xtype: 'datefield',
    fieldLabel: 'Date of Birth',
    name: 'birthDate',
    msgTarget: 'under', // location of the error message
    invalidText: '"{0}" bad. "{1}" good.' // 自定义错误消息文本
}

Custom Error Message

2. 自定义验证

有些验证需求,内置的验证无法满足. 最简单的方法就是使用Text Field’s(文本输入控件) regex配置项应用验证规则和使用maskRe 配置项限制哪些字符可以在控件里输入去实现一种自定义验证. 这里是一个验证时间的文本输入控件的例子.

{
    xtype: 'textfield',
    fieldLabel: 'Last Login Time',
    name: 'loginTime',
    regex: /^([1-9]|1[0-9]):([0-5][0-9])(\s[a|p]m)$/i,
    maskRe: /[\d\s:amp]/i,
    invalidText: 'Not a valid time.  Must be in the format "12:34 PM".'
}

虽然上面的方法适用于验证单个的(输入控件)field,但对于一个有许多共享相同自定义验证的输入控件的应用程序来说,这是不切实际的.

Ext.form.field.VTypes类提供了一个创建可重用的自定义验证的解决方案. 下面展示一个自定义的时间验证器如何被创建:

// custom Vtype for vtype:'time'
var timeTest = /^([1-9]|1[0-9]):([0-5][0-9])(\s[a|p]m)$/i;
Ext.apply(Ext.form.field.VTypes, {
    //  vtype validation function
    time: function(val, field) {
        return timeTest.test(val);
    },
    // vtype Text 属性: 当验证方法返回false的时候显示错误文本信息
    timeText: 'Not a valid time.  Must be in the format "12:34 PM".',
    // vtype Mask 属性: 按键过滤
    timeMask: /[\d\s:amp]/i
});

一旦一个自定义的验证器被创建了,就可以应用于所有的文本输入控件通过使用vtype 配置项:

{
    fieldLabel: 'Last Login Time',
    name: 'loginTime',
    vtype: 'time'
}

请看一个演示的验证例子. 更多关于自定义验证的信息, 请查阅VTypes的API文档.

数据处理

表单提交

提交数据到服务器最简单的一种方法是使用Basic Formurl配置项. 由于Form Panel 封装了Basic Form,所以我们可以直接在Form Panel上使用任何Basic Form的配置项:

Ext.create('Ext.form.Panel', {
    ...
    url: 'add_user',
    items: [
        ...
    ]
});

Form的submit 方法可被用于提交数据到配置的url:

Ext.create('Ext.form.Panel', {
    ...
    url: 'add_user',
    items: [
        ...
    ],
    buttons: [
        {
            text: 'Submit',
            handler: function() {
                var form = this.up('form'); // 获取 form
                if (form.isValid()) { // 提交数据之前确保Form包含有效数据
                    form.submit({
                        success: function(form, action) {
                           Ext.Msg.alert('Success', action.result.msg);
                        },
                        failure: function(form, action) {
                            Ext.Msg.alert('Failed', action.result.msg);
                        }
                    });
                } else { // 如果数据是无效的话显示错误提示
                    Ext.Msg.alert('Invalid Data', 'Please correct form errors.')
                }
            }
        }
    ]
});

上面的例子, 一个button被配置了一个 handler 处理form提交任务. 这个handler采取如下措施:

  1. 首先, 必须获得Form Panel的引用.
  2. 然后,提交数据之前调用isValid 方法确认没有输入控件有验证错误.
  3. 最后,调用 submit 方法, 传递两个回调- successfailure. 在这些回调函数里, action.result 指解析成JSON的回应.

上面的例子预期的JSON回应看起来像这样:

{ "success": true, "msg": "User added successfully" }

Binding a Form to a Model

The Model 类的使用遍及 Ext JS,描述各种类型的数据以及在服务器上检索和更新数据. 一个描述一个User 的模型应该定义一个User有的所有fields(字段)以及加载和保存数据的proxy:

Ext.define('MyApp.model.User', {
    extend: 'Ext.data.Model',
    fields: ['firstName', 'lastName', 'birthDate'],
    proxy: {
        type: 'ajax',
        api: {
            read: 'data/get_user',
            update: 'data/update_user'
        },
        reader: {
            type: 'json',
            root: 'users'
        }
    }
});

数据可以直接被加载到一个 Form PanelModel中通过使用loadRecord 方法:

MyApp.model.User.load(1, { // load user with ID of "1"
    success: function(user) {
        userForm.loadRecord(user); // when user is loaded successfully, load the data into the form
    }
});

最后, 替换submit 方法保存数据, Form Panel的updateRecord 方法被用于更新记录与表单数据, 并且 Model的save 方法被调用保存数据到服务器:

Ext.create('Ext.form.Panel', {
    ...
    url: 'add_user',
    items: [
        ...
    ],
    buttons: [
        {
            text: 'Submit',
            handler: function() {
                var form = this.up('form'), // get the form panel
                    record = form.getRecord(); // get the underlying model instance
                if (form.isValid()) { // make sure the form contains valid data before submitting
                    form.updateRecord(record); // update the record with the form data
                    record.save({ // save the record to the server
                        success: function(user) {
                            Ext.Msg.alert('Success', 'User saved successfully.')
                        },
                        failure: function(user) {
                            Ext.Msg.alert('Failure', 'Failed to save user.')
                        }
                    });
                } else { // display error alert if the data is invalid
                    Ext.Msg.alert('Invalid Data', 'Please correct form errors.')
                }
            }
        }
    ]
});

Model 绑定例子

Layouts

布局在一个Ext JS应用程序里是用来处理组件的大小和位置的. Form Panels 可以使用任何 布局容器. 更多关于Layouts的信息请查阅布局和容器 指导.

例如, 可以很容易完成在一个表单里水平定位一个控件通过使用HBox 布局:

编辑 预览 在Fiddle打开
Ext.create('Ext.form.Panel', {
    renderTo: document.body,
    title: 'User Form',
    height: 120,
    width: 585,
    defaults: {
        xtype: 'textfield',
        labelAlign: 'top',
        padding: 10
    },
    layout: 'hbox',
    items: [
        {
            fieldLabel: 'First Name',
            name: 'firstName'
        },
        {
            fieldLabel: 'Last Name',
            name: 'lastName'
        },
        {
            xtype: 'datefield',
            fieldLabel: 'Date of Birth',
            name: 'birthDate'
        }
    ]
});
Last updated