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:
- Stop editing the grid
- Get the number of records currently in the store
- Grab the currently selected record and store it in memory
- Grab the record type from the store
- 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)
- Alter the start_time value of the new object that was created to today’s date and time
- Insert record into grid
- 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?
Looks to me like it’s not constructing the
tceobject correctly. This line is where you should set your breakpoint:It seems like it’s successfully constructing a
timecardEntrythat 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:
(You should be able to call
grid.store.add(tce)instead ofinsertas you’re inserting at the end.)