I am using ExtJs 3.4. I have a checkbox control in an ExtJs Grid. I want to disable the checkbox control based on when a value in the store is equal to zero.
I have tried this and it does not disable it:
var colModel = new Ext.grid.ColumnModel(
{
columns: [
{ id: 'AircraftOid', header: "AircraftOid", width: 100, sortable: true, locked: true, dataIndex: 'AircraftOid', hidden: true },
{ id: 'nNumber', header: "N-#", width: 100, sortable: true, locked: true, dataIndex: 'NNumber' },
{ header: "Make", width: 150, sortable: true, dataIndex: 'Make' },
{ header: "Model", width: 150, sortable: true, dataIndex: 'Model' },
{ header: "Register",
width: 55,
sortable: true,
dataIndex: 'Register',
xtype: 'checkcolumn'
}
],
isCellEditable: function (col, row) {
return false;
}
});
var grid = new Ext.grid.GridPanel({
store: aircraftStore,
cm: colModel,
sm: new Ext.grid.RowSelectionModel({ singleSelect: true }),
viewConfig: {
forceFit: true
},
height: 100,
split: true,
region: 'north'
});
Thanks in advance.
Your thought was right. But...
First, you're overriding column model's isCellEditable method to prevent editing. But Grid doesn't calls that method. It only works on EditorGrid.
Second, Ext.ux.grid.CheckColumn doesn't handle any editable features, because it's not an editor, it's just a column.
So for my project i modified it to act as a editor and added the readOnly property to prevent editing on normal Grids. If you set readOnly to true, it'll not be clickable anymore.
Ext.ux.grid.CheckColumn = Ext.extend(Ext.grid.Column, {
processEvent : function(name, e, grid, rowIndex, colIndex) {
if ( !this.readOnly && name == 'mousedown' ) {
grid.stopEditing();
var record = grid.store.getAt(rowIndex);
var cm = grid.getColumnModel();
var edit_e = {
grid: grid,
record: record,
field: this.dataIndex,
value: record.data[this.dataIndex],
row: rowIndex,
column: colIndex,
cancel: false
};
if ( grid.fireEvent( 'beforeedit', edit_e ) !== false && !edit_e.cancel ) {
record.set( this.dataIndex, !record.data[this.dataIndex] );
edit_e.cancel = null;
grid.fireEvent( 'afteredit', edit_e );
}
return false;
} else {
return Ext.grid.ActionColumn.superclass.processEvent.apply(this, arguments);
}
},
editable : false,
readOnly : false,
renderer : function(v, p, record){
p.css += ' x-grid3-check-col-td';
return String.format('<div class="x-grid3-check-col{0}"> </div>', v ? '-on' : '');
},
init: Ext.emptyFn
});
Ext.preg('checkcolumn', Ext.ux.grid.CheckColumn);
Ext.grid.CheckColumn = Ext.ux.grid.CheckColumn;
Ext.grid.Column.types.checkcolumn = Ext.ux.grid.CheckColumn;
Related
Conditionally i need to disable the toolbar button based on the grid json data, if status not "New"
tbarItems.push(
"->",
{
text: t('import'),
id: 'masterdata_import',
iconCls: 'pimcore_icon_import',
disabled: false,
scale: 'small',
handler: this.importJob.bind(this),
dataIndex: 'status',
renderer: function (value, rowIndex, record) {
if (value !== 'New') {
tbar.disable();
}
},
}
);
https://i.stack.imgur.com/8hVmN.png
Any idea how to do this?
Thanks
i made an example at sencha fiddle. Take a look:
https://fiddle.sencha.com/#view/editor&fiddle/2qs3
You can bind disabled parameter to parameter from viewModel, while viewModel can be updated e.g when data in store changed (event datachanged is fired).
getLayout: function () {
if (this.layout == null) {
var itemsPerPage = pimcore.helpers.grid.getDefaultPageSize(70);
this.store = pimcore.helpers.grid.buildDefaultStore(
'/admin/referenceapp/import/get-import-files?processed=0',
['date','time','sourceFileLocation','sizeReadable','status','jobReference'],
itemsPerPage,
{autoLoad: true}
);
// only when used in element context
if(this.inElementContext) {
var proxy = this.store.getProxy();
proxy.extraParams["folderDate"] = this.element.folderDate;
} else {
}
this.pagingtoolbar = pimcore.helpers.grid.buildDefaultPagingToolbar(this.store);
var tbarItems = [];
tbarItems.push(
"->",
{
text: t('import'),
id: 'masterdata_import',
iconCls: 'pimcore_icon_import',
//disabled: false,
scale: 'small',
bind: {
disabled: "{one_different_than_new}"
},
handler: this.importJob.bind(this)
}
);
var tbar = Ext.create('Ext.Toolbar', {
cls: 'main-toolbar',
items: tbarItems
});
var columns = [
{text: t("date"), sortable: true, dataIndex: 'date', flex: 100, filter: 'date'},
{text: t("time"), sortable: true, dataIndex: 'time', flex: 100, filter: 'string'},
{text: t("source_file_location"), sortable: true, dataIndex: 'sourceFileLocation', filter: 'string', flex: 200},
{text: t("size"), sortable: true, dataIndex: 'sizeReadable', filter: 'string', flex: 200},
{text: t("status"), sortable: true, dataIndex: 'status', filter: 'string', flex: 200},
{text: t("jobReference"), sortable: true, dataIndex: 'jobReference', filter: 'string', flex: 200},
];
columns.push({
xtype: 'actioncolumn',
menuText: t('delete'),
width: 40,
dataIndex: 'status',
renderer: function (value, rowIndex, record) {
if (value !== 'New') {
rowIndex.tdCls = 'importnotdelete'
}
},
disabled:false,
items: [{
tooltip: t('icon_delete_import'),
icon: "/bundles/pimcoreadmin/img/flat-color-icons/delete.svg",
handler: this.removeVersion.bind(this)
}]
});
var plugins = [];
this.grid = new Ext.grid.GridPanel({
frame: false,
title: t('plugin_referenceapp_masterdataname_importview'),
store: this.store,
region: "center",
columns: columns,
columnLines: true,
bbar: Ext.create('Ext.PagingToolbar', {
pageSize: 0,
store: this.store,
displayInfo: true,
limit:0
}),
tbar: tbar,
stripeRows: true,
autoScroll: true,
plugins: plugins,
viewConfig: {
forceFit: true
},
viewModel: {
data: {
"one_different_than_new": false
}
},
//listeners: {
// afterrender : function(model) {
// console.log(model.store.data.items);
//
// for(i = 0; i<model.store.data.items.length; i++){
//
// if (model.store.data.items[i].status !== 'New') {
// tbar.disable();
// //console.log('test');
// }
//
// else{
// //console.log('no new');
// }
// }
//
// }
//}
});
this.grid.on("rowclick", this.showDetail.bind(this));
this.detailView = new Ext.Panel({
region: "east",
minWidth: 350,
width: 350,
split: true,
layout: "fit"
});
var layoutConf = {
items: [this.grid, this.detailView],
layout: "border",
//closable: !this.inElementContext
};
if(!this.inElementContext) {
//layoutConf["title"] = t('product_versions');
}
this.layout = new Ext.Panel(layoutConf);
this.layout.on("activate", function () {
this.store.load();
var check = function () {
var isDifferentThanNew = false;
this.store.each(function (r) {
if (r.get('status') != 'New') {
isDifferentThanNew = true;
}
});
this.grid.getViewModel().set('one_different_than_new', isDifferentThanNew);
}
// Listen on datachanged and update
this.store.on('update', function (s) {
check();
});
this.store.on('datachanged', function (s) {
check();
});
check();
}.bind(this));
}
return this.layout;
},
I have 2 combo box inside grid. The second combo box value will be change base on first combo box.
For example the combo has 3 item : America, Europe, Asia. If in the first combo box Europe is selected, then in the second combo box, Europe is not appear again.
I don't know which version of extjs I used, but here's the code :
MY COMBO STORE
var cb_group = Ext.create('Ext.data.Store', {
model: 'cb_group',
autoLoad: false,
proxy: {
type: 'ajax',
url: 'srv/master/group/combo',
reader: {
type: 'json',
root: 'rows'
}
}
});
MY COMBO INSIDE GRID
var set_approval_dtl = Ext.create('Ext.Window', {
title: title_approval2, width: 850, height: 395, rowdblclick: true, forceFit: true,
closeAction: "hide", store: ms_set_approval_dtl_store,
defaults: {
sortable: true, resizable: false
},
items: [
{xtype: "form", items: [
{layout: 'column', columnWidth: .5, itemId: 'set_approve', defaults: {border: false},
items: [{xtype: "panel", itemId: "set_approve_panel", height: 330, defaultType: 'textfield', margin: '0 10px 0 10px',
defaults: {labelWidth: 120, width: 850, maxLength: 200},
items: [
{xtype: "grid", itemId: "grid_items", width: 782, height: 280, margin: '0 10px 10px 10px', autoScroll: true,
plugins: Ext.create('Ext.grid.plugin.CellEditing', {clicksToEdit: 1, pluginId: 'rowEditing'}),
store: ms_set_approval_dtl_store, stripeRows: true, defaultType: "gridcolumn",
viewConfig: {forceFit: true},
columns: [
{header: grid18j, width: 150, dataIndex: 'nm_act', align: 'center'},
{header: subtitle_approval3, width: 126, dataIndex: 'level1', align: 'center',
editor: {xtype: "combobox", name: "cdgr", itemId: "cdgr1", typeAhead: true, editable: false, triggerAction: "all", forceSelection: true,
emptyText: grid8k, store: cb_group, valueField: "id", displayField: "nm",
listeners: {
expand: function(field, options, val) {
if (Ext.typeOf(field.getPicker().loadMask) !== "boolean") {
field.getPicker().loadMask.hide();
}
},
select: function(value) {
var obj = this.lastSelection[0].data;
return obj.nm;
this.lastSelection[0].hide;
cb_group.removeAt(0);
}
}},
renderer: function(val) {
var index = cb_group.findExact('id', val);
if (index !== -1) {
var rs = cb_group.getAt(index).data;
return rs.nm;
}
}
},
{header: subtitle_approval4, width: 126, dataIndex: 'level2', align: 'center', itemId: "level2",
editor: {xtype: "combobox", name: "cdgr", itemId: "cdgr2", typeAhead: true, editable: false, triggerAction: "all", forceSelection: true,
emptyText: grid8k, store: cb_group, valueField: "id", displayField: "nm",
listeners: {
expand: function(field, options) {
if (Ext.typeOf(field.getPicker().loadMask) !== "boolean") {
field.getPicker().loadMask.hide();
}
}
}
},
select: function(value) {
var obj = this.lastSelection[0].data;
return obj.nm;
},
renderer: function(val) {
var index = cb_group.findExact('id', val);
if (index !== -1) {
var rs = cb_group.getAt(index).data;
return rs.nm;
}
}
}]
}]}
]}]}
]});
I've tried this.lastSelection[0].hide; and cb_group.removeAt(0); in the first combo. But it didn't work at all. And I dont know why my select listener is not working.
please share some solution. Thanks
You can use XTemplates to manage this kind of behavior with one store and two comboboxes.
At first you have to create an XTemplate for your list of items in the combobox:
// displayfield = displayfield configured in your combobox
var template = Ext.create('Ext.XTemplate',
'<tpl for=".">',
' <tpl if="[Ext.getCmp(\'combobox1\').getValue()] != id && [Ext.getCmp(\'combobox2\').getValue()] != id">',
' <div class="x-boundlist-item">{label}</div>',
' <tpl else>',
' <tpl if="id == null || id == \'\'">',
' <div class="x-boundlist-item">{label}</div>',
' <tpl else>',
' <div class="x-boundlist-item" style="font-size:0px; height:0px;"></div>',
' </tpl>',
' </tpl>',
'</tpl>'
);
The XTemplate contains some statements to check if the specific value is already selected in one of the comboboxes. If not, then the entry will appear in the dropdown list, otherwise it will be hidden. To make it work, you have to set the template in your combobox and add some listeners to them:
// Combobox 1
{
xtype: 'combo',
id: 'combobox1',
store: 'your_store',
tpl: template,
displayField: 'label',
valueField: 'id',
listeners: {
beforeSelect: function (combo, record, index, eOpts)
{
// Check if the selected value is already selected in combobox2
var cbx2value = !!Ext.getCmp('combobox2').getValue() ? Ext.getCmp('combobox2').getValue() : '';
if (cbx2value != record.get('id') && cbx2value != record.get('id')) {
return true; // selected entry will be selected successfully
} else {
return false; // selected entry will not be selected
}
},
change: function ()
{
// Get the picker (list of items) of the other combobox and refresh it's template state
var cbx2picker = Ext.getCmp('combobox2').getPicker();
cbx2picker.refresh();
}
}
// Combobox 2
{
xtype: 'combo',
id: 'combobox2',
store: 'your_store',
tpl: template,
displayField: 'label',
valueField: 'id',
listeners: {
beforeSelect: function (combo, record, index, eOpts)
{
// Check if the selected value is already selected in combobox2
var cbx1value = !!Ext.getCmp('combobox1').getValue() ? Ext.getCmp('combobox1').getValue() : '';
if (cbx1value != record.get('id') && cbx1value != record.get('id')) {
return true; // selected entry will be selected successfully
} else {
return false; // selected entry will not be selected
}
},
change: function ()
{
// Get the picker (list of items) of the other combobox and refresh it's template state
var cbx1picker = Ext.getCmp('combobox1').getPicker();
cbx1picker.refresh();
}
}
It's not the ultimate solution, but for one of my projects it worked like a charm. I have simplified the example as good as possible to make the solution clearer.
You will need two stores, one for each combo box, both filled with the same data.
And then you will do:
combo1.on('select',function(combo, newVal) {
combo2.getStore().filterBy(function(rec){
return rec.get("value")!=newVal;
})
});
I am on ExtJs3.2.
There is a gridpanel with a column having a textField as an editor.
On change of value in the textfield - i need the corresponding row to be highlighted.
How do I get the 'owning' row index of the text field?
columns: [
...........
{header: 'Revenues',dataIndex: 'percentage',
editor: new Ext.form.TextField({
listeners: {
'change' : function (field, newValue, oldValue) {
if(oldValue!=newValue){
.......
//How do I get the row index?
Ext.fly(grid.getView().getRow(row)).addClass('yellow-row');
}
}
}
Is there any other way to achieve this?
Could you please try below?
var grid = Ext.grid.GridPanel({
store: yourStore,
id: 'myGrid',
colModel: new Ext.grid.ColumnModel({
defaults: {
width: 120,
sortable: true
},
columns: [
{id: 'Company', header: 'Company', width: 120, sortable: true, dataIndex: 'company'},
{header: 'Change', dataIndex: 'change'},
{
header: 'Revenue',
dataIndex: 'percentage',
editor: new Ext.form.TextField({
listeners: {
'change': function(field, newValue, oldValue) {
if (oldValue != newValue) {
var sel = Ext.getCmp('myGrid').getSelectionModel().getSelected();
// if you select more than one record use getSelections instead of getSelected
console.log(sel);
}
}
}
})
}
]
}),
sm: new Ext.grid.RowSelectionModel({singleSelect: true}),
width: 500,
height: 300,
frame: true,
title: 'My Grid'
});
Inside of my editorGridPanel, I have a three columns. I want to concatenate the data inside of my 'firstname' and 'lastname' column directly going to or when the cursor or focus are now in my 'email address' column in every row. Could someone help me about this problem?
var cm = new Ext.grid.ColumnModel({
defaults: {
sortable: true
},
columns: [{
id: 'id',
header: 'ID',
dataIndex: 'id',
width: 220,
editable: false,
hidden: true
},
{
id: 'firstname',
header: 'First Name',
dataIndex: 'firstname',
width: 220,
editor: new fm.TextField({
allowBlank: false
}),
listeners: {
click: function(){
Ext.getCmp('b_save').enable();
Ext.getCmp('b_cancel').enable();
}
}
},
{
id: 'lastname',
header: 'Last Name',
dataIndex: 'lastname',
width: 220,
align: 'left',
editor: new fm.TextField({
allowBlank: false
}),
listeners: {
click: function(){
Ext.getCmp('b_save').enable();
Ext.getCmp('b_cancel').enable();
}
}
},
{
id: 'email_address',
header: 'Email Address',
dataIndex: 'email_address',
width: 330,
align: 'left',
editor: new fm.TextField({
allowBlank: false
}),
listeners: {
click: function(){
Ext.getCmp('b_save').enable();
Ext.getCmp('b_cancel').enable();
}
}
},
var grid = new Ext.grid.EditorGridPanel({
viewConfig: {
forceFit: true,
autoFill: true
},
id: 'maingrid',
store: store,
cm: cm,
width: 700,
anchor: '100%',
height: 700,
frame: true,
loadMask: true,
waitMsg: 'Loading...',
clicksToEdit: 2,
sm : new Ext.grid.RowSelectionModel({
singleSelect: true
,onEditorKey : function(field, e) {
if (e.getKey() == e.ENTER) {
var k = e.getKey(), newCell, g = this.grid,ed = g.activeEditor || g.lastActiveEditor;
e.stopEvent();
/*ed.completeEdit();*/
if(e.shiftKey){
newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
}else{
newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
}
if(newCell){
g.startEditing(newCell[0], newCell[1]);
}
}
else if(e.getKey() == e.TAB){
var k = e.getKey(), newCell, g = this.grid,ed = g.activeEditor || g.lastActiveEditor;
e.stopEvent();
newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
if(newCell){
g.startEditing(newCell[0], newCell[1]);
}
}
}
}),
});
You can add concatenated firstname and lastname and set it as value into your email_address field in listener for beforeedit editorgrid event:
listeners: {
beforeedit: function(e) {
if (e.field === 'email_address' && e.value === '') {
var newValue = e.record.get('firstname') + '.' + e.record.get('lastname');
e.record.set('email_address', newValue);
}
}
},
Fiddle with example: https://fiddle.sencha.com/#fiddle/3mf
I have an ExtJs EditorGridPanel with a custom renderer. The basic idea is to display a checkbox when an item needs to be registered and the text Registered when an item is already registered. Everything is working swimmingly except for when clicking on the header, the entire grid re-renders and every cell toggles. Furthermore, the sort does not work. How to I tell when the header has been clicked so that all my checkboxes do not toggle? How do I fix the sort for the column? Right now it does not sort. Thanks in advance for your help.
var colModel = new Ext.grid.ColumnModel(
{
columns: [
{ id: 'ItemOid', header: "ItemOid", width: 100, sortable: true, locked: true, dataIndex: 'ItemOid', hidden: true },
{ id: 'nNumber', header: "N-#", width: 100, sortable: true, locked: true, dataIndex: 'NNumber' },
{ header: "Make", width: 150, sortable: true, dataIndex: 'Make' },
{ header: "Model", width: 150, sortable: true, dataIndex: 'Model' },
{ header: "Register",
width: 55,
sortable: true,
dataIndex: 'Register',
xtype: 'checkcolumn',
renderer: renderFunction
}
]
});
function renderFunction(value, metaData, record, rowIndex, colIndex, store) {
if (!store.getAt(rowIndex).data['ItemNeedsRegistered'])
return 'Registered';
var isRegistered = store.getAt(rowIndex).data['Registered'];
var renderString;
if (initialItemRender || isRegistered) {
renderString = '<input type="checkbox" id="chkRegistered' + rowIndex + '" />';
store.getAt(rowIndex).data['Registered'] = false;
} else {
renderString = '<input type="checkbox" checked="yes" id="chkRegistered' + rowIndex + '" />';
store.getAt(rowIndex).data['Registered'] = true;
}
return renderString;
}
var grid = new Ext.grid.EditorGridPanel({
store: itemStore,
cm: colModel,
sm: new Ext.grid.RowSelectionModel({ singleSelect: true }),
viewConfig: {
forceFit: true
},
height: 100,
split: true,
region: 'north'
});
Here is my second attempt that also fails, by trying to update the underlying value and it does not check or uncheck.
function renderFunction(value, metaData, record, rowIndex, colIndex, store) {
if (!store.getAt(rowIndex).data['ItemNeedsRegistered'])
return 'Registered';
var isRegistered = store.getAt(rowIndex).data['Registered'];
var renderString;
if (initialItemRender || !isRegistered) {
renderString = '<input type="checkbox" id="chkRegistered' + rowIndex + '"'
+ ' onClick="updateStoreOnClick(' + rowIndex + ', true);"'
+ ' />';
} else {
renderString = '<input type="checkbox" checked="yes" id="chkRegistered' + rowIndex + '"'
+ ' onClick="updateStoreOnClick(' + rowIndex + ', false);"'
+ ' />';
}
return renderString;
}
function updateStoreOnClick(rowIndex, value) {
store.getAt(rowIndex).data['Registered'] = value;
}
The toggling problem is occurring because you're directly updating each record's Registered attribute during the render. The next time you cause a render of the grid (e.g., when sorting), the values of all the records' Registered attributes are the boolean opposite of what they were to begin with. You probably shouldn't be changing those attributes during render, but instead find a way to get the correct value from the checkbox just before saving.
For sorting, you can manually create a numeric attribute on your record that contains a semi-arbitrary value specifically for sorting. For example, call the attribute RegisteredSort and give it these values:
1 — items not requiring registration
2 — registered items
3 — unregistered items
Then you use the RegisteredSort attribute as the dataIndex for that column rather than Registered.
I believe the rowIndex will be 0 when you click on the header... How about adding
if(rowIndex == 0) return;
to the top of renderFunction?
I ended up doing a custom check column:
//#region Custom Check Column
AVRMS.AircraftRegisterCheckColumn = Ext.extend(Ext.grid.Column, {
/**
* #private
* Process and refire events routed from the GridView's processEvent method.
*/
processEvent: function(name, e, grid, rowIndex, colIndex) {
if (name == 'mousedown') {
var record = grid.store.getAt(rowIndex);
if (grid.store.getAt(rowIndex).data['AircraftNeedsRegistered'])
record.set(this.dataIndex, !record.data[this.dataIndex]);
return false; // Cancel row selection.
} else {
return Ext.grid.ActionColumn.superclass.processEvent.apply(this, arguments);
}
},
renderer: function(v, p, rec, rowIndex, colIndex, store) {
if (!store.getAt(rowIndex).data['AircraftNeedsRegistered'])
return store.getAt(rowIndex).data['Status'];
p.css += ' x-grid3-check-col-td';
return String.format('<div class="x-grid3-check-col{0}"> </div>', v ? '-on' : '');
},
// Deprecate use as a plugin. Remove in 4.0
init: Ext.emptyFn
});
Ext.reg('airRegChkCol', AVRMS.AircraftRegisterCheckColumn);
// register ptype. Deprecate. Remove in 4.0
Ext.preg('airRegChkCol', AVRMS.AircraftRegisterCheckColumn);
// register Column xtype
Ext.grid.Column.types.airRegChkCol = AVRMS.AircraftRegisterCheckColumn;
//#endregion
//#region ColumnModel
var colModel = new Ext.grid.ColumnModel(
{
columns: [
{ id: 'AircraftOid', header: "AircraftOid", width: 100, sortable: true, locked: true, hideable: false, dataIndex: 'AircraftOid', hidden: true, menuDisabled: true },
{ id: 'nNumber', header: "N-Number", width: 75, sortable: true, locked: true, hideable: false, dataIndex: 'NNumber', menuDisabled: true },
{ header: "Make", width: 150, sortable: true, hideable: false, dataIndex: 'Make', menuDisabled: true },
{ header: "Model", width: 150, sortable: true, hideable: false, dataIndex: 'Model', menuDisabled: true },
{
header: "Airworthy",
width: 75,
sortable: true,
hideable: false,
dataIndex: 'Airworthy',
menuDisabled: true,
renderer: function (value, metaData, record, rowIndex, colIndex, store) {
if (value == true)
return 'Yes';
return 'No';
},
editor: new Ext.form.ComboBox({
id: 'makeCombo',
typeAhead: true,
store: airworthy,
triggerAction: 'all',
forceSelection: true,
mode: 'local',
allowBlank: false,
selectOnFocus: true,
lazyRender: true,
listClass: 'x-combo-list-small'
})
},
{
id: 'Register',
header: "Select to Register",
width: 75,
sortable: true,
dataIndex: 'Register',
xtype: 'airRegChkCol',
hideable: false,
menuDisabled: true
}]
});
//#endregion
//#region grid
var grid = new Ext.grid.EditorGridPanel({
store: aircraftStore,
cm: colModel,
sm: new Ext.grid.RowSelectionModel({ singleSelect: true }),
viewConfig: {
forceFit: true
},
height: 100,
split: true,
region: 'north'
});
//#endregion