A Sencha ExtJS EditorGridPanel automatically visually marks a cell as dirty when a user modifies the value, but that’s it. If you want to know if a row is dirty and take an action based upon that knowledge, you’re on your own.
Since I needed this functionality, I took a stab at it today, and here’s my simplistic example of how to do it.
First, I create a global variable named editedRow which will get updated when the afteredit event is fired on the GridPanel.
var editedRow;
var AutoGrid = new Ext.grid.EditorGridPanel({
// Properties clipped for article;
// view example for full code
});
// After any field is edited, make the row dirty
AutoGrid.on('afteredit', function(){
if (!editedRow){
editedRow = AutoGrid.getSelectionModel().getSelections();
}
}, this);
Now that I’ve stored which row is dirty, every time the user clicks on another cell, I check a) there is a dirty row, and b) if the active row is the dirty row.
// Any time the user mouse downs on a cell,
// check to see if there are any dirty rows
AutoGrid.on('cellmousedown', checkForChanges, this);
function checkForChanges(){
if (!editedRow){
return true; // No dirty rows
} else {
var selectedRow = AutoGrid.getSelectionModel().getSelections();
var selectedRecord = selectedRow[0].data;
var editedRecord;
editedRecord = editedRow[0].data;
if (selectedRecord.model != editedRecord.model){
// Alert the user to save changes
// See example for full code
}
}
}
Then if there is a dirty row, I can prompt the user and ask it to save its changes before editing another row.
Man this took a long time to figure out.
Ok, inside a Sencha ExtJS DataGrid, I have assigned a ComboBox as the editor for one of the columns populated with its own Store of items. I’ve got a ColdFusion Component returning a query object, which is then converted into JSON with the ajaxCFC class.
var ItemCode = Ext.data.Record.create([
{name: 'item_id', type: 'int'}
{name: 'item_code', type: 'string'}
]);
var ItemCodesStore = new Ext.data.Store({
autoLoad:false,
proxy: new Ext.data.MemoryProxy(),
reader: new Ext.data.JsonReader({ root: 'data'; }, ItemCode)
});
// Snippet from ColumnModel of DataGrid
header: 'Code',
dataIndex: 'existingCode',
width: 70,
editor: new Ext.form.ComboBox({
mode: 'local',
displayField: 'item_code',
valueField: 'item_id',
store: ItemCodesStore
})
This is straightforward code. The column represents the existingCode value in the DataGrid’s store, and when the user clicks on an individual cell, a ComboBox is rendered with possible values stored in ItemCodesStore.
My problem is that I want the item_code value displayed at all times. By default, when a user selects an item from the ComboBox, the item_id value will be displayed, because even though I have set displayField:’item_code’ in the ComboBox, the DataGrid has no knowledge of this, and always shows the valueField.
What I had to do was write a custom renderer for that column that does a search in the ItemCodes store for a matching item_id and return the item_code to be rendered instead.
function CodeRenderer(val){
var matching = ItemCodesStore.queryBy(
function(rec,id){
return rec.item_id == val;
});
return (matching.items[0]) ? matching.items[0].data.item_code : '';
};
// Snippet from ColumnModel of DataGrid
header: 'Code',
dataIndex: 'existingCode',
width: 70,
renderer: CodeRenderer,
editor: new Ext.form.ComboBox({
mode: 'local',
displayField: 'item_code',
valueField: 'item_id',
store: ItemCodesStore
})
True to my promise over the years, anytime it takes me significant mental and time resources to discover how to accomplish a development task that I think others might find useful, I will share the process.
I’ve got an app in which users need access to a dataset that is larger than 10k records. Pagination to the rescue (plus a search feature which I covered in my Replacing data in Sencha ExtJS grid store article). I’m giving the users the option of paging through the results 100 at a time if they so wish.
It ended up being simple to accomplish after scouring through the documentation and looking at related articles throughout the Web.
First you need to have a script that returns sets of 100 results. In my case, I have a ColdFusion Component that does a CFQUERY on the table. I simply pass in the number from which I want to start my resultset and it returns the next 100 rows. Convert your query to a JSON string using serializeJSON() in ColdFusion, or any method you wish.
Next, I created a ColdFusion page that accepts a start parameter – which is sent from the PagingBar object in ExtJS – and passes that along to the CFC. The resulting JSON string simply gets output.
<cfsetting enablecfoutputonly="true">
<cfparam default="" name="start">
<cfscript>
providers = application.widget.framework.getBean('Insurance').listInsurance(startRecord=start);
writeOutput(insurers);
</cfscript>
<cfsetting enablecfoutputonly="false">
Next, create a Store object with this page as its proxy, and a JsonReader to parse the results.
var Insurer = Ext.data.Record.create([
{name: 'col1', type: 'int'},
{name: 'col2', type: 'string'},
{name: 'col3', type: 'string'},
{name: 'col4', type: 'int'}
]);
var InsurerStore = new Ext.data.Store({
proxy: new Ext.data.HttpProxy({url: 'liveQueries/insurance.cfm'}),
reader: new Ext.data.JsonReader({ root: 'data', totalProperty:'totalRecords' }, Insurer)
});
Now you can create your PagingBar object with the Store object you created as its datastore.
var PagingBar = new Ext.PagingToolbar({
pageSize: 100,
store: InsurerStore,
displayInfo: true,
displayMsg: 'Displaying topics {0} - {1} of {2}',
emptyMsg: 'No insurers to display'
});
Lastly, attach your PagingBar to a DataGrid object with the bbar property. You also have the option of performing an initial search to show the first 100 record to the user by default. To do this, just call the load() event on your Store (shown below).
var InsurerGrid = new Ext.grid.GridPanel({
store : InsurerStore,
sm : new Ext.grid.RowSelectionModel({singleSelect:true}),
cm : InsurerColumnModel,
renderTo : 'insurer-grid',
frame : true,
bbar : PagingBar
});
InsurerStore.load({params:{start:0, limit:100}});