View
/**
* This example shows a common site registration form. The form appears to be simple but
* it shows a few special things:
* 这个例子展示了一个普通的页面登录表单,这个表单看起来很简单但是他展示了一些比较特别的事儿:
* - The display of field errors has been customized. Fields have `msgTarget: 'none'` so
* the errors are not displayed with the individual fields; instead event listeners are
* attached to the FormPanel to group up all error messages into a custom global error
* indicator, with a persistent tooltip showing the error details.
* field的错误提示是自定义的,fields的属性msgTarget:none,因此错误不是针对单个的field进行提示的,而是设置
* 了针对整个表单的报错。
* - The "Terms of Use" link has an event handler attached so it opens the page in a modal
* Ext.Window.
* 点击Terms of Use会弹出一个窗口
* - The password fields have custom validation attached to verify the user enters the
* same value in both.
*
* - The submit button has `formBind: true` so it is only enabled when the form becomes
* valid.
* 提交按钮绑定了formBind:true,只有在表单有效的时候才能提交
*/
Ext.define('KitchenSink.view.form.CustomErrorHandling', {
extend: 'Ext.form.Panel',
xtype: 'form-customerrors',
controller: 'form-customerrors',
frame: true,
width: 350,
bodyPadding: 10,
bodyBorder: true,
title: 'Account Registration',
defaults: {
anchor: '100%'
},
fieldDefaults: {
labelWidth: 110,
labelAlign: 'left',
msgTarget: 'none',
invalidCls: '' //unset the invalidCls so individual fields do not get styled as invalid
//并没有设置invalidCls,因此单个的fields在无效的时候不会得到样式
},
/*
* Listen for validity change on the entire form and update the combined error icon
* 监听整个表单变化的有效性,并且联合错误图标一起更新
*/
listeners: {
//有效性的监听
validitychange: 'updateErrorState',
//错误信息的监听
errorchange: 'updateErrorState'
},
dockedItems: [{
cls: Ext.baseCSSPrefix + 'dd-drop-ok',
xtype: 'container',
dock: 'bottom',
layout: {
type: 'hbox',
align: 'middle'
},
padding: '10 10 5',
items: [{
xtype: 'component',
reference: 'formErrorState',
height: '100%',
invalidCls: Ext.baseCSSPrefix + 'form-invalid-icon-default',
validCls: Ext.baseCSSPrefix + 'dd-drop-icon',
baseCls: 'form-error-state',
flex: 1,
validText: 'Form is valid',
invalidText: 'Form has errors',
tipTpl: [
'<ul class="' + Ext.baseCSSPrefix + 'list-plain">',
'<tpl for=".">',
'<li><span class="field-name">{name}</span>: ',
'<span class="error">{error}</span>',
'</li>',
'</tpl>',
'</ul>'
],
setErrors: function(errors) {
var me = this,
tpl = me.tipTpl,
tip = me.tip;
if (!me.tipTpl.isTemplate) {
tpl = me.tipTpl = new Ext.XTemplate(tpl);
}
if (!tip) {
tip = me.tip = Ext.widget('tooltip', {
target: me.el,
title: 'Error Details:',
minWidth: 200,
autoHide: false,
anchor: 'top',
mouseOffset: [-11, -2],
closable: true,
constrainPosition: false,
cls: 'errors-tip'
});
}
errors = Ext.Array.from(errors);
// Update CSS class and tooltip content
if (errors.length) {
me.addCls(me.invalidCls);
me.removeCls(me.validCls);
me.update(me.invalidText);
tip.setDisabled(false);
tip.update(tpl.apply(errors));
tip.show();
}
else {
me.addCls(me.validCls);
me.removeCls(me.invalidCls);
me.update(me.validText);
tip.setDisabled(true);
tip.hide();
}
}
}, {
xtype: 'button',
formBind: true,
disabled: true,
text: 'Submit Registration',
minWidth: 140,
listeners: {
click: 'submitRegistration'
}
}]
}],
items: [{
xtype: 'textfield',
name: 'username',
fieldLabel: 'User Name',
allowBlank: false,
minLength: 6
}, {
xtype: 'textfield',
name: 'email',
fieldLabel: 'Email Address',
vtype: 'email',
allowBlank: false
}, {
xtype: 'textfield',
name: 'password1',
fieldLabel: 'Password',
inputType: 'password',
style: 'margin-top: 15px',
allowBlank: false,
minLength: 8
}, {
xtype: 'textfield',
name: 'password2',
fieldLabel: 'Repeat Password',
inputType: 'password',
allowBlank: false,
/*
* Custom validator implementation - checks that the value matches what was entered into
* the password1 field.
*/
validator: function(value) {
var password1 = this.previousSibling('[name=password1]');
return (value === password1.getValue()) ? true : 'Passwords do not match.'
}
},
/*
* Terms of Use acceptance checkbox. Two things are special about this:
* 1) The boxLabel contains a HTML link to the Terms of Use page; a special
* click listener opens this page in a modal Ext window for convenient viewing,
* and the Decline and Accept buttons in the window update the checkbox's state
* automatically.
*(1)boxlabel里面包含了一个html连接。有一个点击监听能够打开这个窗口,这个窗口还有两个按钮分别代表接受和拒绝。
* 2) This checkbox is required, i.e. the form will not be able to be submitted
* unless the user has checked the box. Ext does not have this type of validation
* built in for checkboxes, so we add a custom getErrors method implementation.
* (2)如果想要提交的话。这个checkbox的勾选状态时必须的,Ext中没有这种类型情况的验证,所以我们需要添加一个自定义的getErrors的方法。
*/
{
xtype: 'checkboxfield',
name: 'acceptTerms',
reference: 'acceptTerms',
fieldLabel: 'Terms of Use',
hideLabel: true,
margin: '15 0 0 0',
boxLabel: 'I have read and accept the <a href="#" class="terms">Terms of Use</a>.',
// Listener to open the Terms of Use page link in a modal window
// Note that the listener method itself is defined in the ViewController
// 监听器的方法是在试图控制器里面定义的
listeners: {
click: {
element: 'boxLabelEl',
fn: 'onTermsOfUseElementClick'
}
},
// Custom validation logic - requires the checkbox to be checked
//自定义的验证逻辑
getErrors: function() {
return this.getValue() ? [] : ['You must accept the Terms of Use']
}
}, {
// The window is added to the form's children array to be handled
// by the form's ViewController. In a more complicated case we would
// probably want the window to have its own ViewController.
xtype: 'window',
reference: 'termsOfUseWindow',
closeAction: 'hide',
title: 'Terms of Use',
modal: true,
width: 700,
height: 400,
bodyPadding: '10 20',
scrollable: true,
// Wall of text
loader: {
url: 'resources/data/form/terms-of-use.html',
autoLoad: true
},
buttons: [{
text: 'Decline',
handler: 'declineTermsOfUse'
}, {
text: 'Accept',
handler: 'acceptTermsOfUse'
}]
}],
beforeDestroy: function() {
var error = this.lookupReference('formErrorState');
if (error) {
Ext.destroy(error.tip);
}
this.callParent();
}
});