Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Re-inserting a Record into an extJS Store

The code

Ext.onReady(
    function() {
         Ext.QuickTips.init();
         Ext.namespace('TimeTracker');
         TimeTracker.dataStore = new Ext.data.JsonStore(
            {
                root: 'timecardEntries',
                url: 'php/scripts/timecardEntry.script.php',
                storeId: 'timesheet',
                autoLoad: true,
                autoSave: true,
                writer: new Ext.data.JsonWriter(
                    {
                      encode: true
                    }
                ),
                fields: [
                    {name: 'id', type: 'integer'},
                    {name: 'user_id', type: 'integer'},
                    {name: 'ticket_id', type: 'integer'},
                    {name: 'description', type: 'string'},
                    {name: 'start_time', type: 'date', dateFormat: 'Y-m-d H:i:s'},
                    {name: 'stop_time', type: 'date', dateFormat: 'Y-m-d H:i:s'},
                    {name: 'client_id', type: 'integer'},
                    {name: 'is_billable', type: 'integer'}
                ]
            }
        );
        TimeTracker.timeEntryGrid = new Ext.grid.EditorGridPanel(
            {
                renderTo: Ext.getBody(),
                store: TimeTracker.dataStore,
                autoFit: true,
                height: 500,
                title: 'Timesheet Entries',
                tbar: [
                    {
                        xtype: 'button',
                        text: 'Add Record',
                        iconCls: 'silk-add',
                        handler: function() {
                            var timecardEntry = TimeTracker.timeEntryGrid.getStore().recordType;
                            var tce = new timecardEntry(
                                {
                                    description: 'New Timesheet Entry',
                                    start_time: new Date().format('m/d/Y H:i:s'),
                                    is_billable: 0
                                }
                            )
                                TimeTracker.timeEntryGrid.stopEditing();
                            var newRow = TimeTracker.dataStore.getCount();
                            TimeTracker.dataStore.insert(newRow, tce);
                            TimeTracker.timeEntryGrid.startEditing(newRow, 0);
                        }
                    }
                ],
                view: new Ext.grid.GridView(
                    {
                        autoFill: true
                    }
                ),
                colModel: new Ext.grid.ColumnModel(
                    {
                        defaults: {
                            sortable: true,
                            editable: true
                        },
                        columns: [
                            {
                                id: 'ticket_number',
                                header: 'Ticket #',
                                dataIndex: 'ticket_number',
                                editor: new Ext.form.TextField({allowBlank: true}),
                                renderer: function(value) {
                                    return (!value) ? 'N/A' : value;
                                }
                            },
                            {
                                id: 'description',
                                header: 'Description',
                                dataIndex: 'description',
                                editor: new Ext.form.TextField({allowBlank: false})
                            },
                            {
                                id: 'start_time',
                                header: 'Start',
                                dataIndex: 'start_time',
                                renderer: Ext.util.Format.dateRenderer('m/d/Y h:i A'),
                                editor: new Ext.form.DateField({allowBlank: false})
                            },
                            {
                                id: 'stop_time',
                                header: 'Stop',
                                dataIndex: 'stop_time',
                                renderer: Ext.util.Format.dateRenderer('m/d/Y h:i A'),
                                editor: new Ext.form.DateField({allowBlank: false})
                            },
                            {
                                id: 'client',
                                header: 'Client',
                                dataIndex: 'client_id',
                                renderer: function(value) {
                                    return (!value) ? 'N/A' : value;
                                }
                            },
                            {
                                id: 'billable',
                                header: 'Billable',
                                dataIndex: 'is_billable',
                                renderer: function(value) {
                                    return (!value) ? 'No' : 'Yes';
                                }                     
                            },
                            {
                                id: 'actions',
                                header: null,

                                xtype: 'actioncolumn',
                                items: [
                                   {
                                       icon: 'assets/images/silk_icons/page_copy.png',
                                       iconCls: 'action_icon',
                                       handler: function(grid, rowIndex, columnIndex) {
                                            // THE PROBLEM STARTS HERE
                                            grid.stopEditing();
                                            var newRow = TimeTracker.dataStore.getCount();
                                            recordClone = grid.store.getAt(rowIndex);
                                            recordClone.data.start_time = new Date().format('Y-m-d H:i:s');
                                            grid.store.insert(newRow, recordClone);
                                            grid.startEditing(newRow, 0);
                                       }
                                   },
                                   {
                                       icon: 'assets/images/silk_icons/page_delete.png',
                                       handler: function(grid, rowIndex, columnIndex) {
                                           alert('called');
                                       }
                                   }
                                ]
                            }
                        ]
                    }
                )
            }
        );
    }
);

The Goal

When the user clicks the 'copy' button, that store record is stored into memory, its 'start_time' is set to the current date and time, and it is re-inserted into the store as a new record

The Current Result

I receive the following JS error: Uncaught TypeError: Cannot read property 'data' of undefined

My Question(s)

For starters, I'm not even sure if I'm grabbing the currently selected row's data record properly. Second, I have no idea what the error message I'm getting means.

Any help is, as always, highly appreciated.

Thanks.

Update 1

After some tweaking, here's what I came up with (this modified code for the copy button handler)

                    {
                        id: 'actions',
                        header: null,

                        xtype: 'actioncolumn',
                        items: [
                       {
                               icon: 'assets/images/silk_icons/page_copy.png',
                               iconCls: 'action_icon',
                               handler: function(grid, rowIndex, columnIndex) {
                                    grid.stopEditing();
                                    var newRow = TimeTracker.dataStore.getCount();
                                    var currentRecord = grid.store.getAt(rowIndex);
                                    var timecardEntry = grid.store.recordType;
                                    tce = new timecardEntry(currentRecord.data);
                                    tce.data.start_time = new Date().format('Y-m-d H:i:s');
                                    grid.store.insert(newRow, tce);
                               }
                           },
                           {
                               icon: 'assets/images/silk_icons/page_delete.png',
                               handler: function(grid, rowIndex, columnIndex) {
                                   alert('called');
                               }
                           }
                        ]
                    }

Here's what I'm doing:

  1. Stop editing the grid
  2. Get the number of records currently in the store
  3. Grab the currently selected record and store it in memory
  4. Grab the record type from the store
  5. Make a new instance of the store record type, and pass in the data object from the selected record. The data object is equivalent to the object literal if you were making a new record by hand (see my original 'add button' code for details)
  6. Alter the start_time value of the new object that was created to today's date and time
  7. Insert record into grid
  8. Happy time!

Please critique this code and let me know if there's a better way to do it. Thanks!

Update 2:

                               handler: function(grid, rowIndex, columnIndex) {
                                    grid.stopEditing();
                                    var recordClone = grid.store.getAt(rowIndex).copy();
                                    Ext.data.Record.id(recordClone);
                                    if(recordClone) {
                                        grid.store.add(recordClone);
                                    }
                               }

I updated the code to use the copy and add methods and it does work. However, when I call the add() method I get a 'e is undefined error' but when I refresh the page, the record is inserted despite the error message. Ideas?

like image 824
Levi Hackwith Avatar asked Nov 27 '10 02:11

Levi Hackwith


2 Answers

Looks to me like it's not constructing the tce object correctly. This line is where you should set your breakpoint:

 tce = new timecardEntry(currentRecord.data);

It seems like it's successfully constructing a timecardEntry that somehow isn't a proper record. Having a poke at just what it is constructing may help.

If it's not apparent from poking at it that way why it's up the spout, try doing it like this, like @timdev suggests:

var store = grid.store,
  currentRecord = store.getAt(rowIndex),
  tce;
tce = currentRecord.copy();
tce.set('start_time', new Date().format('Y-m-d H:i:s'));

if (tce) {
  store.add(tce);
}

(You should be able to call grid.store.add(tce) instead of insert as you're inserting at the end.)

like image 68
wombleton Avatar answered Nov 03 '22 06:11

wombleton


Really well-written question. Good bit of relevant code, and nice explanation of what you're stuck on. Unfortunately, I don't see anything that stands out.

Your script looks mostly right. You're close to being where you need to be.

Below is an answer that I just typed out, and then reread your question (and code), and thought a little better of. You probably know this stuff already, but it's here for anyone else. It's also relevant, because I don't see any errors in the relevant part of what you did, so you probably blew it somewhere else. The questions are: where and how?

Hopefully someone less exhausted than i am will come along and find the obvious problem, in the meantime, here's my scrawl about how to debug in Ext and why:


You've left something important out, or overlooked it. That error message you mentioned: Uncaught TypeError: Cannot read property 'data' of undefined -- where is that happening? It looks like it's not happening in the code you posted, it might very well be happening down in the bowels of ExtJS.

So, fire up FireBug, and turn on the "break on error" feature. Make your error happen, and start looking at the "stack" pane over on the right (usually). The stack will show you how you got to where you are.

Unless I'm missing something (and since I'm just running your code in my head, I very well may be), there's probably something misconfigured elsewhere that's causing your bug.

But as with any program (and especially with ExtJS, in my experience), the debugger is your friend.

Do this:

  • Use the -debug version of ext-base.js and ext-all.js (until it all works)
  • Use firebug, and "break on errors"
  • Learn to use the debugger to step through code, and to watch the data you're operating on.
  • Don't give up when you find yourself deep in the bowels of ExtJS. If you try, you'll start to get a sense of WTF is going on, and even if you don't understand it all, it will start to give you hints about where you screwed up.
like image 1
timdev Avatar answered Nov 03 '22 06:11

timdev