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