Hi I have added one context menu on my grid which will perform the enable and disable functionality for selected row. I am new to ExtJs. I have added below listener for the grid. How to add enable and disable functionality for the grid row?
listeners: {
itemcontextmenu: function (grid, record, item, index, e) {
var contextMenu = Ext.create('Ext.menu.Menu', {
controller: 'grid-controller',
width: 165,
plain: true,
items: [{
text: 'Disable',
listeners: {
click: {fn: 'disable', extra: record}
},
}]
});
e.stopEvent();
contextMenu.showAt(e.getXY());
}
}
This is not a copy-paste answer, but going through the following steps with doing your own research you can solve your problem.
1. Create the context menu only once and destroy it
In you code, the context menu is created every time when the user opens up the menu on the grid. This is not good. Instead, create the context menu only once when the grid is created, and destroy it when the grid is destroyed. Something like this:
Ext.define('MyGrid', {
extend: 'Ext.grid.Panel',
initComponent : function() {
this.callParent();
this.MyMenu = Ext.create('Ext.menu.Menu', {
items: [...]
});
this.on({
scope : this,
itemcontextmenu : this.onItemContextMenu
});
},
onDestroy : function() {
if (this.MyMenu) {
this.MyMenu.destroy();
}
},
onItemContextMenu : function(view, rec, item,index, event) {
event.stopEvent();
this.MyMenu.showAt(event.getXY());
}
});
2. Store enabled / disabled state in the record
For the next step to work, records in your grid must contain whether the corresponding row is enabled or disabled. In the context menu, when user selects enabled / disabled, store this status like this, get record of the row where the context menu was displayed from:
record.set('myDisabledState', true); // or false
It is important to store the disabled state (and not enabled), because when your grid initially is rendered, these values won't be in the records, so record.get('myDisabledState') will evaluate to FALSE, and that is the desired behaviour, if you want to start with every row being able to be selected.
3. Disable selection
Now you can add a beforeselect listener to your grid, see documentation. This listeners receives record as parameter, and if you return false from this listener, the selection will be canceled. So in this listener simply add:
listeners: {
beforeselect: function ( grid, record, index, eOpts ) {
return !record.get('myDisabledState');
}
}
4. Apply formatting - OPTIONAL
It is likely that you want to add different formatting for disabled rows, for example grey colour. The easiest way to do it is to add a custom CSS style to your Application.scss file:
.my-disabled-row .x-grid-cell-inner {
color: gray;
}
Finally add getRowClass configuration to your grid, it will receive the current record being rendered, and you can return the above custom CSS style when the row is disabled:
Ext.define('MyGrid', {
// your grid definition
,
viewConfig: {
getRowClass: function (record, rowIndex, rowParams, store) {
if (record.get('myDisabledState')) {
return "my-disabled-row";
}
}
}
});
In this last part, when row is not disabled, it will return nothing, so default formatting will be used.
Related
I have a two context menu items inside my grid. The first one is "delete" and the second one is Disable or Enable. Delete context menu I have added as below
var contextMenu = Ext.create('Ext.menu.Menu', {
controller: 'sites',
width: 250,
plain: true,
items: [{
text: 'Delete',
handler: function () {
},
}]
Now I wanted to add Disable or Enable inside the items as a context menu. By enable or disable I mean I need to check the state of that particular row of the grid i.e. if the state of the row is enabled then "Disable" option should be come in the context menu and if the state is disables then the "Enable" option should be come in the context menu. How can I check the state of the row and how can I put if else condition inside my items? Below is the column for checking the enabling of the row.
columns: [
{text:'Active',dataIndex:'enabled',flex:1 },
]
You can use an actioncolumn to do so. It renders an icon in the grid cell, where you can link a function thanks to the handler config.
Here you can check with the record parameter whether the selected row is active, and render conditionally the right option; for example:
handler: function(view, rowIndex, colIndex, item, e, record, eOpts) {
if (record.data.active) {
openDisableMenu()
} else {
openEnableMenu()
}
}
I have a sample code from extjs, the action is part of multi column of an column where I have edit, delete, duplicate. I want to disable the delete icon based on another field value. I have an another column called IS_USED which returns true/false. The delete button should be disable if IS_USED is true.
I tried to write the handler within action but is not working.
I am new in extjs, any help or workaround is appreciable.
action: {
iconCls: 'x-icon-cross-on',
text: terms.del,
url: url.destroy,
useAjax: true,
confirm: terms.confirm,
handler: function(grid, record, action, domEl, response) {
if ( !response.success) {
test.ui.Msg.flash(response.message, test.ui.Msg.ERR);
javascript.scroll(0,0);
} else {
test.ui.Msg.success(response.message);
grid.getStore().reload();
}
}
}
The best practice is just bind the "disabled" property to the button directly based on the record value.
first, set viewModel:true to the grid.
{
xtype: 'grid',
//add this below
itemConfig:{
viewModel:true
},
//....others props like columns, with,etc....
and the last, in your button add this:
action: {
iconCls: 'x-icon-cross-on',
//add this
bind:{
disabled:"{record.IS_USED}" //the logic is placed here
},
//.....other props....
You can also bind any other bindable properties as like hidden, text, etc by using this trick.
Hope this can help you.
I have a grid with a checkbox selection model.
Ext.define('Mb.view.ship.OrdersGrid', {
extend: 'Ext.grid.Panel',
selType: 'checkboxmodel',
selModel: {
injectCheckbox: 0,
pruneRemoved: false
},
...
There are some rows that shold not be selectable, based on a value in a field.
In a normal column, I can intervene in the display with renderer and hide the cell content with css (metadata.tdCls), but for the auto generated checkbox column, I cannot find a method to disable or hide the checkbox on a row basis.
Does anyone have an idea how to do this ?
You simply use the beforeselect event of the grid. Returning false, will not allow the selection. Check the documentation.
Ext.define('Mb.view.ship.OrdersGrid', {
extend: 'Ext.grid.Panel',
selType: 'checkboxmodel',
selModel: {
injectCheckbox: 0,
pruneRemoved: false
},
listeners: {
beforeselect: function(grid, record, index, eOpts) {
if (record.get('yourProperty')) {//replace this with your logic.
return false;
}
}
}
..........
If you really want to hide the checkbox, you could add CSS classes for your grid rows, and using them you could may be hide them. Check this answer for a solution.
In ExtJS 6 overriding renderer will not work.
You can get around that by defining viewConfig with getRowClass:
getRowClass: function(record) {
var classes = '';
if (!record.get('available')) {
classes += ' selection-disabled';
}
return classes;
}
Then in your CSS add this:
.selection-disabled .x-selmodel-column {
visibility: hidden;
}
That will hide selection checkbox.
Now to disable selection by clicking on a row use the standard method. I.e. add a beforeselect to listeners to selModel:
selModel: {
selType: 'checkboxmodel',
showHeaderCheckbox: false,
listeners: {
beforeselect: function(grid, record) {
if (!record.get('available')) {
return false;
}
}
}
},
CheckboxSelectionModel also has a renderer.
var sm = new Ext.grid.CheckboxSelectionModel({
checkOnly : true,
renderer : function(v,p,record) {
// First condition : show
if (record.data.XXX == 'YYYY') return '<div class="x-grid3-row-checker"> </div>';
// else hide
else return '';
},
header: ''
});
https://www.sencha.com/forum/showthread.php?122496-How-to-hide-certain-checkbox-in-a-CheckboxSelectionModel
Returning empty '' also disables checkbox selection, not only by hiding it but also adding unselectable="on" to the parent div.
Don't know about doing it inside an Ext.define (never had the need to extend) , but seems feasible.
UPDATE: Despite having unselectable="on", clicking on the row (if enabled), or using the header checkbox (select-all) will select "disabled" rows. It may be a good idea to implement a listener then.
I've posted this over on the Sencha forums, wanted to also post it here just in case:
I have a GridPanel that utilizes a PagingToolbar and a CheckboxSelectionModel. I want to keep track of selections across pages. I'm nearly there, but I'm running into issues with the PagingToolbar controls (such as next page) firing a 'selectionchange' event on the my selection model.
Here's a simplified sample of my code:
Code:
var sm = Ext.create('Ext.selection.CheckboxModel', {
listeners:{
selectionchange: function(selectionModel, selectedRecords, options){
console.log("Selection Change!!");
// CODE HERE TO KEEP TRACK OF SELECTIONS/DESELECTIONS
}
}
});
var grid = Ext.create('Ext.grid.Panel', {
autoScroll:true,
store: store,
defaults: {
sortable:true
},
selModel: sm,
dockedItems: [{
xtype: 'pagingtoolbar',
store: store,
dock: 'bottom',
displayInfo: true
}],
listeners: {'beforerender' : {fn:function(){
store.load({params:params});
}}}
});
store.on('load', function() {
console.log('loading');
console.log(params);
console.log('selecting...');
var records = this.getNewRecords();
var recordsToSelect = getRecordsToSelect(records);
sm.select(recordsToSelect, true, true);
});
I assumed that I could select the records on the load event and not trigger any events.
What's happening here is that the selectionchange event is being triggered on changing the page of data and I don't want that to occur. Ideally, only user clicking would be tracked as 'selectionchange' events, not any other component's events bubbling up and triggering the event on my selection model. Looking at the source code, the only event I could see that fires on the PagingToolbar is 'change'. I was trying to follow how that is handled by the GridPanel, TablePanel, Gridview, etc, but I'm just not seeing the path of the event. Even then, I'm not sure how to suppress events from the PagingToolbar to the SelectionModel.
Thanks in advance,
Tom
I've managed to handle that. The key is to detect where page changes. Easiest solution is to set buffer for selection listener and check for Store.loading property.
Here is my implementation of selection model:
var selModel = Ext.create('Ext.selection.CheckboxModel', {
multipageSelection: {},
listeners:{
selectionchange: function(selectionModel, selectedRecords, options){
// do not change selection on page change
if (selectedRecords.length == 0 && this.store.loading == true && this.store.currentPage != this.page) {
return;
}
// remove selection on refresh
if (this.store.loading == true) {
this.multipageSelection = {};
return;
}
// remove old selection from this page
this.store.data.each(function(i) {
delete this.multipageSelection[i.id];
}, this);
// select records
Ext.each(selectedRecords, function(i) {
this.multipageSelection[i.id] = true;
}, this);
},
buffer: 5
},
restoreSelection: function() {
this.store.data.each(function(i) {
if (this.multipageSelection[i.id] == true) {
this.select(i, true, true);
}
}, this);
this.page = this.store.currentPage;
}
And additional binding to store is required:
store.on('load', grid.getSelectionModel().restoreSelection, grid.getSelectionModel());
Working sample: http://jsfiddle.net/pqVmb/
Lolo's solution is great but it seems that it doesn't work anymore with ExtJS 4.2.1.
Instead of 'selectionchange' use this:
deselect: function( selectionModel, record, index, eOpts ) {
delete this.multipageSelection[i.id];
},
select: function( selectionModel, record, index, eOpts ) {
this.multipageSelection[i.id] = true;
},
This is a solution for ExtJs5, utilizing MVVC create a local store named 'selectedObjects' in the View Model with the same model as the paged grid.
Add select and deselect listeners on the checkboxmodel. In these functions add or remove the selected or deselected record from this local store.
onCheckboxModelSelect: function(rowmodel, record, index, eOpts) {
// Add selected record to the view model store
this.getViewModel().getStore('selectedObjects').add(record);
},
onCheckboxModelDeselect: function(rowmodel, record, index, eOpts) {
// Remove selected record from the view model store
this.getViewModel().getStore('selectedObjects').remove(record);
},
On the pagingtoolbar, add a change listener to reselect previously seleted records when appear in the page.
onPagingtoolbarChange: function(pagingtoolbar, pageData, eOpts) {
// Select any records on the page that have been previously selected
var checkboxSelectionModel = this.lookupReference('grid').getSelectionModel(),
selectedObjects = this.getViewModel().getStore('selectedObjects').getRange();
// true, true params. keepselections if any and suppresses select event. Don't want infinite loop listeners.
checkboxSelectionModel.select(selectedObjects, true, true);
},
After whatever action is complete where these selections are no longer needed. Call deselectAll on the checkboxmodel and removeAll from the local store if it will not be a destroyed view. (Windows being closed, they default set to call destroy and will take care of local store data cleanup, if that is your case)
I have created a form that displays values in plain displayfields.
There is an "edit" button next to the form and once clicked by the user, the displayfields should switch to being textfields and will, therefore, make the data editable.
This, I am guessing, would be achieved by having two identical forms, one editable and one not and one or the other would be visible, based on the user having clicked the button. Another way, perhaps, is to have the xtype dynamically selected upon clicking the button.
Can anybody point me towards a certain direction in order to do this? I am a complete newbie to ExtJS and only just started learning ExtJS4.
Thank you in advance.
M.
Start by rendering all fields as input fields with disabled:true. Then use this for the Edit button handler:
...
form.getForm().getFields().each(function(field) {
field.setDisabled( false); //use this to enable/disable
// field.setVisible( true); use this to show/hide
}, form );//to use form in scope if needed
Ext.getCmp('yourfieldid').setFieldStyle('{color:black; border:0; background-color:yourcolor; background-image:none; padding-left:0}');
Ext.getCmp('yourfieldid').setReadOnly(true);
You can toggle based on a property isEditable. Then when you click the button you change the property and just remove and add the form. It makes it cleaner if you are switching back and forth.
Ext.define('E.view.profile.information.Form', {
extend: 'Ext.form.Panel',
xtype: 'form',
title: 'Form',
layout: 'fit',
initComponent: function () {
this.items = this.buildItems();
this.callParent();
},
buildItems: function () {
return [this.buildInvestmentPhilosophy()];
},
buildInvestmentPhilosophy: function () {
var field = {
name: 'investmentPhilosophy',
xtype: 'displayfield',
editableType: 'textarea',
grow: true,
maxLength: 6000,
value: '---',
renderer: E.Format.textFormatter
};
this.toggleEditingForForm(field);
return field;
},
toggleEditingForForm: function (form) {
if (this.isEditable) {
Ext.Array.each(form, this.configureFieldForEditing, this);
}
},
configureFieldForEditing: function (field) {
if (field.editableType) {
field.xtype = field.editableType;
}
}
});
You can also try to have two items : a displayfield and a textfield with the same data source and you could hide/show the right item with your button handler.
You should not have any CSS problems
(If you did not have CSS problems I would enjoy to see you code)