Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / CellEditing.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-grid-plugin-CellEditing'>/**
19 </span> * The Ext.grid.plugin.CellEditing plugin injects editing at a cell level for a Grid. Only a single
20  * cell will be editable at a time. The field that will be used for the editor is defined at the
21  * {@link Ext.grid.column.Column#editor editor}. The editor can be a field instance or a field configuration.
22  *
23  * If an editor is not specified for a particular column then that cell will not be editable and it will
24  * be skipped when activated via the mouse or the keyboard.
25  *
26  * The editor may be shared for each column in the grid, or a different one may be specified for each column.
27  * An appropriate field type should be chosen to match the data structure that it will be editing. For example,
28  * to edit a date, it would be useful to specify {@link Ext.form.field.Date} as the editor.
29  *
30  *     @example
31  *     Ext.create('Ext.data.Store', {
32  *         storeId:'simpsonsStore',
33  *         fields:['name', 'email', 'phone'],
34  *         data:{'items':[
35  *             {&quot;name&quot;:&quot;Lisa&quot;, &quot;email&quot;:&quot;lisa@simpsons.com&quot;, &quot;phone&quot;:&quot;555-111-1224&quot;},
36  *             {&quot;name&quot;:&quot;Bart&quot;, &quot;email&quot;:&quot;bart@simpsons.com&quot;, &quot;phone&quot;:&quot;555--222-1234&quot;},
37  *             {&quot;name&quot;:&quot;Homer&quot;, &quot;email&quot;:&quot;home@simpsons.com&quot;, &quot;phone&quot;:&quot;555-222-1244&quot;},
38  *             {&quot;name&quot;:&quot;Marge&quot;, &quot;email&quot;:&quot;marge@simpsons.com&quot;, &quot;phone&quot;:&quot;555-222-1254&quot;}
39  *         ]},
40  *         proxy: {
41  *             type: 'memory',
42  *             reader: {
43  *                 type: 'json',
44  *                 root: 'items'
45  *             }
46  *         }
47  *     });
48  *
49  *     Ext.create('Ext.grid.Panel', {
50  *         title: 'Simpsons',
51  *         store: Ext.data.StoreManager.lookup('simpsonsStore'),
52  *         columns: [
53  *             {header: 'Name',  dataIndex: 'name', editor: 'textfield'},
54  *             {header: 'Email', dataIndex: 'email', flex:1,
55  *                 editor: {
56  *                     xtype: 'textfield',
57  *                     allowBlank: false
58  *                 }
59  *             },
60  *             {header: 'Phone', dataIndex: 'phone'}
61  *         ],
62  *         selType: 'cellmodel',
63  *         plugins: [
64  *             Ext.create('Ext.grid.plugin.CellEditing', {
65  *                 clicksToEdit: 1
66  *             })
67  *         ],
68  *         height: 200,
69  *         width: 400,
70  *         renderTo: Ext.getBody()
71  *     });
72  */
73 Ext.define('Ext.grid.plugin.CellEditing', {
74     alias: 'plugin.cellediting',
75     extend: 'Ext.grid.plugin.Editing',
76     requires: ['Ext.grid.CellEditor', 'Ext.util.DelayedTask'],
77
78     constructor: function() {
79 <span id='Ext-grid-plugin-CellEditing-event-beforeedit'>        /**
80 </span>         * @event beforeedit
81          * Fires before cell editing is triggered. Return false from event handler to stop the editing.
82          *
83          * @param {Object} e An edit event with the following properties:
84          *
85          * - grid - The grid
86          * - record - The record being edited
87          * - field - The field name being edited
88          * - value - The value for the field being edited.
89          * - row - The grid table row
90          * - column - The grid {@link Ext.grid.column.Column Column} defining the column that is being edited.
91          * - rowIdx - The row index that is being edited
92          * - colIdx - The column index that is being edited
93          * - cancel - Set this to true to cancel the edit or return false from your handler.
94          */
95 <span id='Ext-grid-plugin-CellEditing-event-edit'>        /**
96 </span>         * @event edit
97          * Fires after a cell is edited. Usage example:
98          *
99          *     grid.on('edit', function(editor, e) {
100          *         // commit the changes right after editing finished
101          *         e.record.commit();
102          *     };
103          *
104          * @param {Ext.grid.plugin.Editing} editor
105          * @param {Object} e An edit event with the following properties:
106          *
107          * - grid - The grid
108          * - record - The record that was edited
109          * - field - The field name that was edited
110          * - value - The value being set
111          * - originalValue - The original value for the field, before the edit.
112          * - row - The grid table row
113          * - column - The grid {@link Ext.grid.column.Column Column} defining the column that was edited.
114          * - rowIdx - The row index that was edited
115          * - colIdx - The column index that was edited
116          */
117 <span id='Ext-grid-plugin-CellEditing-event-validateedit'>        /**
118 </span>         * @event validateedit
119          * Fires after a cell is edited, but before the value is set in the record. Return false from event handler to
120          * cancel the change.
121          *
122          * Usage example showing how to remove the red triangle (dirty record indicator) from some records (not all). By
123          * observing the grid's validateedit event, it can be cancelled if the edit occurs on a targeted row (for
124          * example) and then setting the field's new value in the Record directly:
125          *
126          *     grid.on('validateedit', function(editor, e) {
127          *       var myTargetRow = 6;
128          *
129          *       if (e.row == myTargetRow) {
130          *         e.cancel = true;
131          *         e.record.data[e.field] = e.value;
132          *       }
133          *     });
134          *
135          * @param {Ext.grid.plugin.Editing} editor
136          * @param {Object} e An edit event with the following properties:
137          *
138          * - grid - The grid
139          * - record - The record being edited
140          * - field - The field name being edited
141          * - value - The value being set
142          * - originalValue - The original value for the field, before the edit.
143          * - row - The grid table row
144          * - column - The grid {@link Ext.grid.column.Column Column} defining the column that is being edited.
145          * - rowIdx - The row index that is being edited
146          * - colIdx - The column index that is being edited
147          * - cancel - Set this to true to cancel the edit or return false from your handler.
148          */
149         this.callParent(arguments);
150         this.editors = Ext.create('Ext.util.MixedCollection', false, function(editor) {
151             return editor.editorId;
152         });
153         this.editTask = Ext.create('Ext.util.DelayedTask');
154     },
155     
156     onReconfigure: function(){
157         this.editors.clear();
158         this.callParent();    
159     },
160
161 <span id='Ext-grid-plugin-CellEditing-method-destroy'>    /**
162 </span>     * @private
163      * AbstractComponent calls destroy on all its plugins at destroy time.
164      */
165     destroy: function() {
166         var me = this;
167         me.editTask.cancel();
168         me.editors.each(Ext.destroy, Ext);
169         me.editors.clear();
170         me.callParent(arguments);
171     },
172     
173     onBodyScroll: function() {
174         var ed = this.getActiveEditor();
175         if (ed &amp;&amp; ed.field) {
176             if (ed.field.triggerBlur) {
177                 ed.field.triggerBlur();
178             } else {
179                 ed.field.blur();
180             }
181         }
182     },
183
184     // private
185     // Template method called from base class's initEvents
186     initCancelTriggers: function() {
187         var me   = this,
188             grid = me.grid,
189             view = grid.view;
190             
191         view.addElListener('mousewheel', me.cancelEdit, me);
192         me.mon(view, 'bodyscroll', me.onBodyScroll, me);
193         me.mon(grid, {
194             columnresize: me.cancelEdit,
195             columnmove: me.cancelEdit,
196             scope: me
197         });
198     },
199
200 <span id='Ext-grid-plugin-CellEditing-method-startEdit'>    /**
201 </span>     * Starts editing the specified record, using the specified Column definition to define which field is being edited.
202      * @param {Ext.data.Model} record The Store data record which backs the row to be edited.
203      * @param {Ext.data.Model} columnHeader The Column object defining the column to be edited. @override
204      */
205     startEdit: function(record, columnHeader) {
206         var me = this,
207             value = record.get(columnHeader.dataIndex),
208             context = me.getEditingContext(record, columnHeader),
209             ed;
210
211         record = context.record;
212         columnHeader = context.column;
213
214         // Complete the edit now, before getting the editor's target
215         // cell DOM element. Completing the edit causes a view refresh.
216         me.completeEdit();
217
218         context.originalValue = context.value = value;
219         if (me.beforeEdit(context) === false || me.fireEvent('beforeedit', context) === false || context.cancel) {
220             return false;
221         }
222         
223         // See if the field is editable for the requested record
224         if (columnHeader &amp;&amp; !columnHeader.getEditor(record)) {
225             return false;
226         }
227         
228         ed = me.getEditor(record, columnHeader);
229         if (ed) {
230             me.context = context;
231             me.setActiveEditor(ed);
232             me.setActiveRecord(record);
233             me.setActiveColumn(columnHeader);
234
235             // Defer, so we have some time between view scroll to sync up the editor
236             me.editTask.delay(15, ed.startEdit, ed, [me.getCell(record, columnHeader), value]);
237         } else {
238             // BrowserBug: WebKit &amp; IE refuse to focus the element, rather
239             // it will focus it and then immediately focus the body. This
240             // temporary hack works for Webkit and IE6. IE7 and 8 are still
241             // broken
242             me.grid.getView().getEl(columnHeader).focus((Ext.isWebKit || Ext.isIE) ? 10 : false);
243         }
244     },
245
246     completeEdit: function() {
247         var activeEd = this.getActiveEditor();
248         if (activeEd) {
249             activeEd.completeEdit();
250         }
251     },
252
253     // internal getters/setters
254     setActiveEditor: function(ed) {
255         this.activeEditor = ed;
256     },
257
258     getActiveEditor: function() {
259         return this.activeEditor;
260     },
261
262     setActiveColumn: function(column) {
263         this.activeColumn = column;
264     },
265
266     getActiveColumn: function() {
267         return this.activeColumn;
268     },
269
270     setActiveRecord: function(record) {
271         this.activeRecord = record;
272     },
273
274     getActiveRecord: function() {
275         return this.activeRecord;
276     },
277
278     getEditor: function(record, column) {
279         var me = this,
280             editors = me.editors,
281             editorId = column.getItemId(),
282             editor = editors.getByKey(editorId);
283
284         if (editor) {
285             return editor;
286         } else {
287             editor = column.getEditor(record);
288             if (!editor) {
289                 return false;
290             }
291
292             // Allow them to specify a CellEditor in the Column
293             if (!(editor instanceof Ext.grid.CellEditor)) {
294                 editor = Ext.create('Ext.grid.CellEditor', {
295                     editorId: editorId,
296                     field: editor
297                 });
298             }
299             editor.parentEl = me.grid.getEditorParent();
300             // editor.parentEl should be set here.
301             editor.on({
302                 scope: me,
303                 specialkey: me.onSpecialKey,
304                 complete: me.onEditComplete,
305                 canceledit: me.cancelEdit
306             });
307             editors.add(editor);
308             return editor;
309         }
310     },
311     
312     // inherit docs
313     setColumnField: function(column, field) {
314         var ed = this.editors.getByKey(column.getItemId());
315         Ext.destroy(ed, column.field);
316         this.editors.removeAtKey(column.getItemId());
317         this.callParent(arguments);
318     },
319
320 <span id='Ext-grid-plugin-CellEditing-method-getCell'>    /**
321 </span>     * Gets the cell (td) for a particular record and column.
322      * @param {Ext.data.Model} record
323      * @param {Ext.grid.column.Column} column
324      * @private
325      */
326     getCell: function(record, column) {
327         return this.grid.getView().getCell(record, column);
328     },
329
330     onSpecialKey: function(ed, field, e) {
331         var grid = this.grid,
332             sm;
333         if (e.getKey() === e.TAB) {
334             e.stopEvent();
335             sm = grid.getSelectionModel();
336             if (sm.onEditorTab) {
337                 sm.onEditorTab(this, e);
338             }
339         }
340     },
341
342     onEditComplete : function(ed, value, startValue) {
343         var me = this,
344             grid = me.grid,
345             sm = grid.getSelectionModel(),
346             activeColumn = me.getActiveColumn(),
347             dataIndex;
348
349         if (activeColumn) {
350             dataIndex = activeColumn.dataIndex;
351
352             me.setActiveEditor(null);
353             me.setActiveColumn(null);
354             me.setActiveRecord(null);
355             delete sm.wasEditing;
356     
357             if (!me.validateEdit()) {
358                 return;
359             }
360             // Only update the record if the new value is different than the
361             // startValue, when the view refreshes its el will gain focus
362             if (value !== startValue) {
363                 me.context.record.set(dataIndex, value);
364             // Restore focus back to the view's element.
365             } else {
366                 grid.getView().getEl(activeColumn).focus();
367             }
368             me.context.value = value;
369             me.fireEvent('edit', me, me.context);
370         }
371     },
372
373 <span id='Ext-grid-plugin-CellEditing-method-cancelEdit'>    /**
374 </span>     * Cancels any active editing.
375      */
376     cancelEdit: function() {
377         var me = this,
378             activeEd = me.getActiveEditor(),
379             viewEl = me.grid.getView().getEl(me.getActiveColumn());
380
381         me.setActiveEditor(null);
382         me.setActiveColumn(null);
383         me.setActiveRecord(null);
384         if (activeEd) {
385             activeEd.cancelEdit();
386             viewEl.focus();
387         }
388     },
389
390 <span id='Ext-grid-plugin-CellEditing-method-startEditByPosition'>    /**
391 </span>     * Starts editing by position (row/column)
392      * @param {Object} position A position with keys of row and column.
393      */
394     startEditByPosition: function(position) {
395         var me = this,
396             grid = me.grid,
397             sm = grid.getSelectionModel(),
398             editRecord = grid.store.getAt(position.row),
399             editColumnHeader = grid.headerCt.getHeaderAtIndex(position.column);
400
401         if (sm.selectByPosition) {
402             sm.selectByPosition(position);
403         }
404         me.startEdit(editRecord, editColumnHeader);
405     }
406 });</pre>
407 </body>
408 </html>