Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / examples / form / registration.js
1 Ext.require([
2     'Ext.form.*',
3     'Ext.Img',
4     'Ext.tip.QuickTipManager'
5 ]);
6
7 Ext.onReady(function() {
8     Ext.tip.QuickTipManager.init();
9
10     var formPanel = Ext.widget('form', {
11         renderTo: Ext.getBody(),
12         frame: true,
13         width: 350,
14         bodyPadding: 10,
15         bodyBorder: true,
16         title: 'Account Registration',
17
18         defaults: {
19             anchor: '100%'
20         },
21         fieldDefaults: {
22             labelAlign: 'left',
23             msgTarget: 'none',
24             invalidCls: '' //unset the invalidCls so individual fields do not get styled as invalid
25         },
26
27         /*
28          * Listen for validity change on the entire form and update the combined error icon
29          */
30         listeners: {
31             fieldvaliditychange: function() {
32                 this.updateErrorState();
33             },
34             fielderrorchange: function() {
35                 this.updateErrorState();
36             }
37         },
38
39         updateErrorState: function() {
40             var me = this,
41                 errorCmp, fields, errors;
42
43             if (me.hasBeenDirty || me.getForm().isDirty()) { //prevents showing global error when form first loads
44                 errorCmp = me.down('#formErrorState');
45                 fields = me.getForm().getFields();
46                 errors = [];
47                 fields.each(function(field) {
48                     Ext.Array.forEach(field.getErrors(), function(error) {
49                         errors.push({name: field.getFieldLabel(), error: error});
50                     });
51                 });
52                 errorCmp.setErrors(errors);
53                 me.hasBeenDirty = true;
54             }
55         },
56
57         items: [{
58             xtype: 'textfield',
59             name: 'username',
60             fieldLabel: 'User Name',
61             allowBlank: false,
62             minLength: 6
63         }, {
64             xtype: 'textfield',
65             name: 'email',
66             fieldLabel: 'Email Address',
67             vtype: 'email',
68             allowBlank: false
69         }, {
70             xtype: 'textfield',
71             name: 'password1',
72             fieldLabel: 'Password',
73             inputType: 'password',
74             style: 'margin-top:15px',
75             allowBlank: false,
76             minLength: 8
77         }, {
78             xtype: 'textfield',
79             name: 'password2',
80             fieldLabel: 'Repeat Password',
81             inputType: 'password',
82             allowBlank: false,
83             /**
84              * Custom validator implementation - checks that the value matches what was entered into
85              * the password1 field.
86              */
87             validator: function(value) {
88                 var password1 = this.previousSibling('[name=password1]');
89                 return (value === password1.getValue()) ? true : 'Passwords do not match.'
90             }
91         },
92
93         /*
94          * Terms of Use acceptance checkbox. Two things are special about this:
95          * 1) The boxLabel contains a HTML link to the Terms of Use page; a special click listener opens this
96          *    page in a modal Ext window for convenient viewing, and the Decline and Accept buttons in the window
97          *    update the checkbox's state automatically.
98          * 2) This checkbox is required, i.e. the form will not be able to be submitted unless the user has
99          *    checked the box. Ext does not have this type of validation built in for checkboxes, so we add a
100          *    custom getErrors method implementation.
101          */
102         {
103             xtype: 'checkboxfield',
104             name: 'acceptTerms',
105             fieldLabel: 'Terms of Use',
106             hideLabel: true,
107             style: 'margin-top:15px',
108             boxLabel: 'I have read and accept the <a href="http://www.sencha.com/legal/terms-of-use/" class="terms">Terms of Use</a>.',
109
110             // Listener to open the Terms of Use page link in a modal window
111             listeners: {
112                 click: {
113                     element: 'boxLabelEl',
114                     fn: function(e) {
115                         var target = e.getTarget('.terms'),
116                             win;
117                         if (target) {
118                             win = Ext.widget('window', {
119                                 title: 'Terms of Use',
120                                 modal: true,
121                                 html: '<iframe src="' + target.href + '" width="950" height="500" style="border:0"></iframe>',
122                                 buttons: [{
123                                     text: 'Decline',
124                                     handler: function() {
125                                         this.up('window').close();
126                                         formPanel.down('[name=acceptTerms]').setValue(false);
127                                     }
128                                 }, {
129                                     text: 'Accept',
130                                     handler: function() {
131                                         this.up('window').close();
132                                         formPanel.down('[name=acceptTerms]').setValue(true);
133                                     }
134                                 }]
135                             });
136                             win.show();
137                             e.preventDefault();
138                         }
139                     }
140                 }
141             },
142
143             // Custom validation logic - requires the checkbox to be checked
144             getErrors: function() {
145                 return this.getValue() ? [] : ['You must accept the Terms of Use']
146             }
147         }],
148
149         dockedItems: [{
150             xtype: 'container',
151             dock: 'bottom',
152             layout: {
153                 type: 'hbox',
154                 align: 'middle'
155             },
156             padding: '10 10 5',
157
158             items: [{
159                 xtype: 'component',
160                 id: 'formErrorState',
161                 baseCls: 'form-error-state',
162                 flex: 1,
163                 validText: 'Form is valid',
164                 invalidText: 'Form has errors',
165                 tipTpl: Ext.create('Ext.XTemplate', '<ul><tpl for="."><li><span class="field-name">{name}</span>: <span class="error">{error}</span></li></tpl></ul>'),
166
167                 getTip: function() {
168                     var tip = this.tip;
169                     if (!tip) {
170                         tip = this.tip = Ext.widget('tooltip', {
171                             target: this.el,
172                             title: 'Error Details:',
173                             autoHide: false,
174                             anchor: 'top',
175                             mouseOffset: [-11, -2],
176                             closable: true,
177                             constrainPosition: false,
178                             cls: 'errors-tip'
179                         });
180                         tip.show();
181                     }
182                     return tip;
183                 },
184
185                 setErrors: function(errors) {
186                     var me = this,
187                         baseCls = me.baseCls,
188                         tip = me.getTip();
189
190                     errors = Ext.Array.from(errors);
191
192                     // Update CSS class and tooltip content
193                     if (errors.length) {
194                         me.addCls(baseCls + '-invalid');
195                         me.removeCls(baseCls + '-valid');
196                         me.update(me.invalidText);
197                         tip.setDisabled(false);
198                         tip.update(me.tipTpl.apply(errors));
199                     } else {
200                         me.addCls(baseCls + '-valid');
201                         me.removeCls(baseCls + '-invalid');
202                         me.update(me.validText);
203                         tip.setDisabled(true);
204                         tip.hide();
205                     }
206                 }
207             }, {
208                 xtype: 'button',
209                 formBind: true,
210                 disabled: true,
211                 text: 'Submit Registration',
212                 width: 140,
213                 handler: function() {
214                     var form = this.up('form').getForm();
215
216                     /* Normally we would submit the form to the server here and handle the response...
217                     form.submit({
218                         clientValidation: true,
219                         url: 'register.php',
220                         success: function(form, action) {
221                            //...
222                         },
223                         failure: function(form, action) {
224                             //...
225                         }
226                     });
227                     */
228
229                     if (form.isValid()) {
230                         Ext.Msg.alert('Submitted Values', form.getValues(true));
231                     }
232                 }
233             }]
234         }]
235     });
236
237 });