I modified the following example code to checkbox model. Here is the link
http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.grid.plugin.DragDrop
Two questions, first:
When dragging an item, all the selected items are being moved too. How to drag only one item each time?
Another question:
When dragging an item, it is forced to become selected. How to make it remain state unchange? (keep unselected when it is unselected before the drag, and vice versa)
And I am using version 4.2.1.
Here is the code modified from the given example:
Ext.onReady(function () {
Ext.create('Ext.data.Store', {
storeId: 'simpsonsStore',
fields: ['name'],
data: [
["Lisa"],
["Bart"],
["Homer"],
["Marge"]
],
proxy: {
type: 'memory',
reader: 'array'
}
});
Ext.create('Ext.grid.Panel', {
store: 'simpsonsStore',
selModel: {mode: 'SIMPLE'}, //added
selType: 'checkboxmodel', //added
columns: [{
header: 'Name',
dataIndex: 'name',
flex: true
}],
viewConfig: {
plugins: {
ptype: 'gridviewdragdrop',
dragText: 'Drag and drop to reorganize'
}
},
height: 200,
width: 400,
renderTo: Ext.getBody()
});
});
Thank you!
You need to overwrite the dragZone in the DragDrop plugin, so it is only sending this record.
the drag has a mousedown event, which is selecting the rows in the grid (because this has a mousedown event too), so it's fired before drag ends.
To understand this I explain this events (for more info w3schools:
row selection event: this is a mousedown event on a grid row.
row drag event: drag = mousepress + (optional) mousemove, BUT: mousepress doesn't really exist so it decides it with the help of time between mousedown and mouseup
the time measurement is done with delayedTasks
if mouseup fired before the delayed time, then it will not be executed, else drag starts
row drop event: drop = dragged + mouseup
There are more ways to prevent this:
try to put the selection to another event, which is fired after drag starts, but it can be messy because this event is used lots of times...
it's selecting it on mousedown, but we deselect it on drag start event and at drop we prevent the selection, I do this in the code.
The working code:
Ext.create('Ext.data.Store', {
storeId:'simpsonsStore',
fields:['name'],
data: [["Lisa"], ["Bart"], ["Homer"], ["Marge"]],
proxy: {
type: 'memory',
reader: 'array'
}
});
Ext.create('Ext.grid.Panel', {
store: 'simpsonsStore',
selModel: {mode: 'SIMPLE'}, //added
selType: 'checkboxmodel', //added
columns: [
{header: 'Name', dataIndex: 'name', flex: true}
],
viewConfig: {
plugins: {
ptype: 'gridviewdragdrop',
dragText: 'Drag and drop to reorganize',
onViewRender : function(view) {
var me = this,
scrollEl;
if (me.enableDrag) {
if (me.containerScroll) {
scrollEl = view.getEl();
}
me.dragZone = new Ext.view.DragZone({
view: view,
ddGroup: me.dragGroup || me.ddGroup,
dragText: me.dragText,
containerScroll: me.containerScroll,
scrollEl: scrollEl,
//to remember if the row was selected originally or not
onBeforeDrag: function(data, e) {
var me = this,
view = data.view,
selectionModel = view.getSelectionModel(),
record = view.getRecord(data.item);
if (!selectionModel.isSelected(record)) {
data.rowSelected = false;
}
return true;
},
onInitDrag: function(x, y) {
var me = this,
data = me.dragData,
view = data.view,
selectionModel = view.getSelectionModel(),
record = view.getRecord(data.item);
//for deselect the dragged record
if (selectionModel.isSelected(record) && data.rowSelected == false) {
selectionModel.deselect(record, true);
}
//added the original row so it will handle that in the drag drop
data.records = [record];
me.ddel.update(me.getDragText());
me.proxy.update(me.ddel.dom);
me.onStartDrag(x, y);
return true;
}
});
}
if (me.enableDrop) {
me.dropZone = new Ext.grid.ViewDropZone({
view: view,
ddGroup: me.dropGroup || me.ddGroup,
//changed the selection at the end of this method
handleNodeDrop : function(data, record, position) {
var view = this.view,
store = view.getStore(),
index, records, i, len;
if (data.copy) {
records = data.records;
data.records = [];
for (i = 0, len = records.length; i < len; i++) {
data.records.push(records[i].copy());
}
} else {
data.view.store.remove(data.records, data.view === view);
}
if (record && position) {
index = store.indexOf(record);
if (position !== 'before') {
index++;
}
store.insert(index, data.records);
}
else {
store.add(data.records);
}
if (view != data.view) {
view.getSelectionModel().select(data.records);
}
}
});
}
}
}
},
height: 200,
width: 400,
renderTo: Ext.getBody()
});
Thanks to Alexander's reply. After reading his reply, I get into the related source code of Extjs. And finally solved the problem of changing state back immediately instead of keep it remains unchange. The code:
Ext.onReady(function () {
Ext.create('Ext.data.Store', {
storeId: 'simpsonsStore',
fields: ['name'],
data: [
["Lisa"],
["Bart"],
["Homer"],
["Marge"]
],
proxy: {
type: 'memory',
reader: 'array'
}
});
Ext.create('Ext.grid.Panel', {
store: 'simpsonsStore',
/* Start: Code block added to the original example */
selModel: {mode: 'SIMPLE', onRowMouseDown: Ext.emptyFn /* throw away onRowMouseDown handler to answer Q2 */},
selType: 'checkboxmodel',
listeners: {
afterrender: function(){
/* override the original handleNodeDrop function to answer Q1 */
this.view.plugins[0].dropZone.handleNodeDrop = function(data, record, position) {
var view = this.view,
store = view.getStore(),
index, records, i, len;
if (data.copy) {
records = data.records;
data.records = [];
for (i = 0, len = records.length; i < len; i++) {
data.records.push(records[i].copy());
}
} else {
data.view.store.remove(data.records, data.view === view);
}
if (record && position) {
index = store.indexOf(record);
if (position !== 'before') {
index++;
}
store.insert(index, data.records);
}
else {
store.add(data.records);
}
// view.getSelectionModel().select(data.records);
};
/* override the original onInitDrag function to answer Q2 */
this.view.plugins[0].dragZone.onInitDrag = function(x, y){
var me = this,
data = me.dragData,
view = data.view,
selectionModel = view.getSelectionModel(),
record = view.getRecord(data.item);
// if (!selectionModel.isSelected(record)) {
// selectionModel.select(record, true);
// }
// data.records = selectionModel.getSelection();
data.records = [selectionModel.lastFocused];
me.ddel.update(me.getDragText());
me.proxy.update(me.ddel.dom);
me.onStartDrag(x, y);
return true;
};
}
},
/* End: Code block added to the original example */
columns: [{
header: 'Name',
dataIndex: 'name',
flex: true
}],
viewConfig: {
plugins: {
ptype: 'gridviewdragdrop',
dragText: 'Drag and drop to reorganize'
}
},
height: 200,
width: 400,
renderTo: Ext.getBody()
});
});
If anyone is interested in 4.1.1 Solution here is the modified Alexander's code that keeps previously selected rows selected after drop.
I slightly modified onInitDrag to select already-selected row back on drag start,
and handleNodeDrop to get it selected on drop.
Ext.create('Ext.data.Store', {
storeId:'simpsonsStore',
fields:['name'],
data: [["Lisa"], ["Bart"], ["Homer"], ["Marge"]],
proxy: {
type: 'memory',
reader: 'array'
}
});
Ext.create('Ext.grid.Panel', {
store: 'simpsonsStore',
selModel: {mode: 'SIMPLE'}, //added
selType: 'checkboxmodel', //added
columns: [
{header: 'Name', dataIndex: 'name', flex: true}
],
resizable: true,
viewConfig: {
plugins: {
ptype: 'gridviewdragdrop',
dragText: 'Drag and drop to reorganize',
onViewRender : function(view) {
var me = this,
scrollEl;
if (me.enableDrag) {
if (me.containerScroll) {
scrollEl = view.getEl();
}
me.dragZone = new Ext.view.DragZone({
view: view,
ddGroup: me.dragGroup || me.ddGroup,
dragText: me.dragText,
containerScroll: me.containerScroll,
scrollEl: scrollEl,
//to remember if the row was selected originally or not
onBeforeDrag: function(data, e) {
var me = this,
view = data.view,
selectionModel = view.getSelectionModel(),
record = view.getRecord(data.item);
if (!selectionModel.isSelected(record)) {
data.rowSelected = false;
} else {
data.rowSelected = true;
}
return true;
},
onInitDrag: function(x, y) {
var me = this,
data = me.dragData,
view = data.view,
selectionModel = view.getSelectionModel(),
record = view.getRecord(data.item);
//to deselect the dragged record
if (selectionModel.isSelected(record) && data.rowSelected == false) {
selectionModel.deselect(record, true);
} else {
selectionModel.select(record, true);
}
//added the original row so it will handle that in the drag drop
data.records = [record];
me.ddel.update(me.getDragText());
me.proxy.update(me.ddel.dom);
me.onStartDrag(x, y);
return true;
}
});
}
if (me.enableDrop) {
me.dropZone = new Ext.grid.ViewDropZone({
view: view,
ddGroup: me.dropGroup || me.ddGroup,
//changed the selection at the end of this method
handleNodeDrop : function(data, record, position) {
var view = this.view,
store = view.getStore(),
selectionModel = view.getSelectionModel(),
index, records, i, len;
if (data.copy) {
records = data.records;
data.records = [];
for (i = 0, len = records.length; i < len; i++) {
data.records.push(records[i].copy());
}
} else {
data.view.store.remove(data.records, data.view === view);
}
if (record && position) {
index = store.indexOf(record);
if (position !== 'before') {
index++;
}
store.insert(index, data.records);
}
else {
store.add(data.records);
}
//select row back on drop if it was selected
if (data.rowSelected) {
selectionModel.select(data.records, true);
}
if (view != data.view) {
view.getSelectionModel().select(data.records);
}
}
});
}
}
}
},
height: 200,
width: 400,
renderTo: Ext.getBody()
});
PS: easiest way to test - https://fiddle.sencha.com/#view/editor
just select 4.1.1 and copy-paste.
Related
I have a grid with thousands of records. It works almost fine. When I programmatically call this method:
selectionModel.selectAll(true);
it works great. My script is not freezed, because of this true parameter, which according to docs suppresses any select events. However, when I select all records via a header checkbox (which selects and deselects all records), my script gets freezed. I guess, it is because by default select events are not suppressed. I tried to find a config, which globally supresses select events, but could not find it. So, my question is how can I fix this issue? How can I globally suppress select events in my grid selModel?
You can handle using overriding onHeaderClick method of grid CheckboxModel.
In this Fiddle, I have created a demo using same method onHeaderClick.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
var store = Ext.create('Ext.data.Store', {
fields: ['number'],
data: (() => {
let data = [];
for (let i = 1; i <= 50000; i++) {
data.push({
'number': i
})
}
return data;
})()
});
Ext.create('Ext.grid.Panel', {
title: 'Demo',
store: store,
itemId: 'demogrid',
columns: [{
text: 'Number',
flex: 1,
dataIndex: 'number'
}],
height: window.innerHeight,
renderTo: Ext.getBody(),
selModel: {
checkOnly: false,
mode: 'SIMPLE',
onHeaderClick: function (headerCt, header, e) {
var me = this,
store = me.store,
isChecked, records, i, len,
selections, selection;
if (me.showHeaderCheckbox !== false && header === me.column && me.mode !== 'SINGLE') {
e.stopEvent();
isChecked = header.el.hasCls(Ext.baseCSSPrefix + 'grid-hd-checker-on');
if (isChecked) {
console.time();
me.deselectAll(true);
console.timeEnd();
} else {
console.time();
me.selectAll(true);
console.timeEnd();
}
}
}
},
selType: 'checkboxmodel',
buttons: [{
text: 'Select All',
handler: function (btn) {
var grid = btn.up('#demogrid');
console.time();
grid.getSelectionModel().selectAll(true);
console.timeEnd();
}
}, {
text: 'Deselect All',
handler: function (btn) {
var grid = btn.up('#demogrid');
console.time()
grid.getSelectionModel().deselectAll(true);
console.timeEnd();
}
}]
});
}
});
use suspendEvents function on model to stop all events and after you done you can start all events by resumeEvents
grid.getSelectionModel().suspendEvents();
grid.getSelectionModel().resumeEvents();
I am new to ext js and I am trying to hide the fourth tab on my screen based on certain entity condition. As, I have coded I am able to disable
(blur) the 4th Setting tab, but the hidden or hide() function is failing.
Basically, I want to hide the fourth tab in items Payment.PaymentSettingsCfg on certain condition.
Any help would really appreciate, thanks in advance.
var bsdataloded = false;
Payment.PaymentSettingsCfg = {
id: 'PaymentSettingsPanel',
title: getMsg('PaymentAdmin', 'PaymentSettingsHeader'),
xtype: 'PaymentSettingsPanels',
listeners: {
activate: function() {
if (!bsdataloded) {
this.loadSettings();
bsdataloded = true;
}
}
}
}
var hidePaymentSettingcfg = false;
debugger;
if (Payment.EntitySettings &&
Payment.EntSettings["EntSITE|Payment_SWitch"] === "Y") {
Payment.PaymentSettingsCfg.disabled = true; //working
// Payment.PaymentSettingsCfg.hidden = true;// not working, even hide() not working
hidePaymentSettingcfg = true;
}
init: function() {
Ext.QuickTips.init();
Ext.state.Manager.setProvider(new Ext.state.CookieProvider({
expires: null
}));
app = new Payment.admin.AppContainer({
id: 'main-panel',
title: Payment.getMsg('PaymentAdmin', 'PaymentConfHeader'),
el: 'bodydiv',
border: true,
layout: 'fit',
defaults: {
border: false
},
items: [{
xtype: 'tabpanel',
activeTab: 0,
width: 500,
deferredRender: false,
hidden: false,
defaults: {
border: false
},
items: [
Payment.PaymentItemCfg,
Payment.PaymentPeriodCfg,
Payment.PaymentTypeCfg,
Payment.PaymentSettingsCfg
]
}]
});
app.render();
}
};
}();
Here is the example to hide and show the tab based on if condition
i am hiding and showing the tab on checkbox checking but you can get your idea
i hope it will help you
here is the Fiddle...
Added the logic to the listeners and it worked.
listeners : {
afterrender : function(){
var testTab = this.getTabEl(3);
if (Payment.EntSettings["EntSITE|Payment_SWitch"] === "Y") {
testTab.hide();
}
}
}
I am building a website using MVC 4, Web API, and Kendo UI controls.
On my page I am using a Kendo UI Listview to filter my grid. I'm trying to add an "ALL" option as the first item in my listview.
Here is the listview:
var jobsfilter = $("#jobfilter").kendoListView({
selectable: "single",
loadOnDemand: false,
template: "<div class='pointercursor' id=${FilterId}>${FilterName}</div>",
dataSource: filterDataSource,
change: function (e) {
var itm = this.select().index(), dataItem = this.dataSource.view()[itm];
if (dataItem.FilterId !== 0) {
var $filter = new Array();
$filter.push({ field: "JobStatusId", operator: "eq", value: dataItem.FilterId });
jgrid.dataSource.filter($filter);
} else {
jgrid.dataSource.filter({});
}
}
});
Here is my datasource:
var filterDataSource = new kendo.data.DataSource({
transport: {
read: {
url: "api/Filter"
}
},
schema: {
model: { id: "FilterId" }
}
});
I have tried a few different methods to make this happen:
I can make it work if I attach it to a button - but I need it there
when the data loads.
If I add it to the dataBound event of the listview, it causes the
databound event to go into a loop and adds the item a bunch (IE) or kills the browser (firefox). Adding preventDefault did nothing.
I've read up on adding a function to the Read paramter of the
datasource, but I think that is simply not the correct place to do
it.
Based on what I've read, I think that I should be able to do it in the dataBound event of the listview and that my implementation is incorrect. Here is the listview with dataBound event added that crashes my browser (Firefox) - or adds about 50 "All" items to the listview (IE).
var jobsfilter = $("#jobfilter").kendoListView({
selectable: "single",
loadOnDemand: false,
template: "<div class='pointercursor' id=${FilterId}>${FilterName}</div>",
dataSource: {
transport: {
read: {
url: "api/Filter"
}
}
},
dataBound: function (e) {
var dsource = $("#jobfilter").data("kendoListView").dataSource;
dsource.insert(0, { FilterId: 0, FilterName: "All" });
e.preventDefault();
},
change: function (e) {
var itm = this.select().index(), dataItem = this.dataSource.view()[itm];
if (dataItem.FilterId !== 0) {
var $filter = new Array();
$filter.push({ field: "JobStatusId", operator: "eq", value: dataItem.FilterId });
jgrid.dataSource.filter($filter);
} else {
jgrid.dataSource.filter({});
}
}
});
Any help would be greatly appreciated.
Why don't you add it server-side?
Anyway, if you want to do it in dataBound, just check whether it exists and only add if it doesn't:
dataBound: function (e) {
var dsource = this.dataSource;
if (dsource.at(0).FilterName !== "All") {
dsource.insert(0, {
FilterId: 0,
FilterName: "All"
});
}
},
As an explanation to the problem you're seeing: you're creating an infinite loop since inserting an element in the data source will trigger the change event and the list view will refresh and bind again (and thus trigger dataBound).
You could also encapsulate this in a custom widget:
(function ($, kendo) {
var ui = kendo.ui,
ListView = ui.ListView;
var CustomListView = ListView.extend({
init: function (element, options) {
// base call to widget initialization
ListView.fn.init.call(this, element, options);
this.dataSource.insert(0, {
FilterId: 0,
FilterName: "All"
});
},
options: {
name: "CustomListView"
}
});
ui.plugin(CustomListView);
})(window.jQuery, window.kendo);
Trying to create an inline edit form.
I have a form that looks like this:
var editPic = "<img src='https://s3.amazonaws.com/bzimages/pencil.png' alt='edit' height='24' width='24' style='margin-left: 10px;'/>";
var submitPic = "<img id='submitPic' src='https://s3.amazonaws.com/bzimages/submitPic.png' alt='edit' height='24' width='24'/>";
Ext.define('BM.view.test.Edit', {
extend: 'Ext.form.Panel',
alias: 'widget.test-edit',
layout: 'anchor',
title: 'Edit Test',
defaultType: 'displayfield',
items: [
{name: 'id', hidden: true},
{
name: 'name',
fieldLabel: 'Name',
afterSubTpl: editPic,
cls: 'editable'
},
{
name: 'nameEdit',
fieldLabel: 'Name',
xtype: 'textfield',
hidden: true,
cls: 'editMode',
allowBlank: false,
afterSubTpl: submitPic
}
]
});
The controller looks like this (a lot of events):
init: function() {
this.control({
'test-edit > displayfield': {
afterrender: this.showEditable
},
'test-edit': {
afterrender: this.formRendered
},
'test-edit > field[cls=editMode]': {
specialkey: this.editField,
blur: this.outOfFocus
}
});
},
outOfFocus: function(field, event) {
console.log('Lost focus');
this.revertToDisplayField(field);
},
revertToDisplayField: function(field) {
field.previousNode().show();
field.hide();
},
formRendered: function(form) {
Ext.get('submitPic').on('click', function (event, object) {
var field = Ext.get(object).parent().parent().parent().parent();
var cmp = Ext.ComponentQuery.query('test-edit > field[cls=editMode]');
});
},
editField: function(field, e) {
var value = field.value;
if (e.getKey() === e.ENTER) {
if (!field.allowBlank && Ext.isEmpty(value)){
console.log('Not permitted!');
} else {
var record = Ext.ComponentQuery.query('test-edit')[0].getForm().getRecord();
Ext.Ajax.request({
url: '../webapp/tests/update',
method:'Post',
params: {
id: record.getId(),
fieldName: field.name,
fieldValue: field.value
},
store: record.store,
success: function(response, t){
field.previousNode().setValue(value);
t.store.reload();
var text = response.responseText;
// process server response here
console.log('Update successful!');
}
});
}
this.revertToDisplayField(field);
} else if (e.getKey() === e.ESC) {
console.log('gave up');
this.revertToDisplayField(field);
}
},
showEditable: function(df) {
df.getEl().on("click", handleClick, this, df);
function handleClick(e, t, df){
e.preventDefault();
var editable = df.nextNode();
editable.setValue(df.getValue());
editable.show();
editable.focus();
df.hide();
}
},
I'm using the 'afterSubTpl' config to add the edit icon, and the accept icon.
I have listeners set up to listen on click events concerning them, but after they are clicked, I only have the element created by Ext.get('submitPic'). Now I want to have access to the the Ext field and form that surround it. The parent method only brings back other DOM elements. How do I connect between them? You can see what I tried in formRendered.
I hope someone can clarify this little bit for me.
Walk up the DOM tree until you find a component for the element's id:
getCmpFromEl = function(el) {
var body = Ext.getBody();
var cmp;
do {
cmp = Ext.getCmp(el.id);
el = el.parentNode;
} while (!cmp && el !== body);
return cmp;
}
Ext.Component.from(el) does exactly this since ExtJS 6.5.0, as I just learnt. Doc
Source
You can get the component by id, but only if your component and its dom element have the same id (they usually do):
Ext.getCmp(yourelement.id)
But this is not exactly good practice -- it would be better to set up your listeners so that the handler methods already have a reference to the component. For example, in your 'submitPic' component, you could define the click listener like this:
var me = this;
me.on({
click: function(arguments){
var cmp = me;
...
});
How to disable the delete button using if condition in Extjs for ex;i want to disable the button if it satifies the given if condition else remain enabled.
if(validAction(entityHash.get('entity.xyz'),actionHash.get('action.delete')))
This is the grid Delete button code.
Ext.reg("gridheaderbar-inActive", Ad.GridInActiveButton,{
xtype: 'tbspacer', width: 5
});
Ad.GridCampDeleteButton = Ext.extend(Ext.Toolbar.Button, {
//text: 'Delete',
cls: 'ad-img-button',
width:61,
height:40,
iconCls: 'ad-btn-icon',
icon: '/webapp/resources/images/btn_del.png',
handler:function(){
statusChange(this.parentBar.parentGrid, 'Delete')
}
});
create actioncolumn and make custom renderer:
{
xtype: 'actioncolumn',
width: 38,
renderer: function (val, metadata, record) {
this.items[0].icon = '${CONTEXT_PATH}/images/' + record.get('fileType') + '.png';
this.items[0].disabled = !record.get('isDownloadActionEnable');
this.items[1].disabled = !record.get('isDeleteActionEnable');
metadata.style = 'cursor: pointer;';
return val;
},
items: [
{
icon: '${CONTEXT_PATH}/images/pdf.png', // Use a URL in the icon config
tooltip: 'Download',
handler: function (grid, rowIndex, colIndex) {
//handle
}
},
{
icon: '${CONTEXT_PATH}/images/delete.png', // Use a URL in the icon config
tooltip: 'Delete',
handler: function (grid, rowIndex, colIndex) {
handle
}
}
]
}
in this example You see additionally how to change dynamically icon.
One way to solve it is to attach a unique ID to your delete button and bind a listener to the selectionchange event of your SelectionModel, whenever the selection changes you can check whatever you want and enable/disable the button as you see fit.
ie.
Ad.GridCampDeleteButton = Ext.extend(Ext.Toolbar.Button, {
id: 'btnDelete',
cls: 'ad-img-button',
...
});
and in your selectionmodel do something like this :
var sm = new Ext.grid.CheckboxSelectionModel({
...
,listeners: {
'selectionchange' : {
fn: function(sm) {
if (sm.hasSelection()) {
var selected = sm.getSelected();
if (selected.get('field') == value) {
Ext.getCmp('btnDelete').disable();
}
else {
Ext.getCmp('btnDelete').enable();
}
}
}
,scope: this
}
}
});