2
votes

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!

3

3 Answers

3
votes
  1. You need to overwrite the dragZone in the DragDrop plugin, so it is only sending this record.

  2. 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:

  1. row selection event: this is a mousedown event on a grid row.
  2. 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
  3. row drop event: drop = dragged + mouseup

    There are more ways to prevent this:

    1. 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...
    2. 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()
});
0
votes

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()
    });
});
0
votes

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.