ExtJS Maximum call stack size exceeded when reorde

2019-08-12 15:09发布

I'm reordering the hierarchy of a tree with drag and drop. After moving multiple nodes I get the error Uncaught RangeError: Maximum call stack size exceeded. The error appears in NodeInterface.js. The updateInfo function crashes in the following line

for (i = 0; i < childCount; i++) { children[i].updateInfo(commit, childInfo); }

What could cause this problem?

The following code shows how I implemnted the drag and drop and reordering in ExtJS 6.5.2. Maybe you can find what's causing the problem.

Plugin

Ext.define('test.component.plugin.TreeDragger', {
extend: 'Ext.AbstractPlugin',
alias: 'plugin.treedrag',

mixins: ['Ext.mixin.Observable'],

constructor: function (config) {
    this.mixins.observable.constructor.call(this, config);
},

init: function (component) {
    var me = this;

    this.source = new Ext.drag.Source({
        element: component.element,
        handle: '.x-gridrow',
        constrain: {
            element: true,
            vertical: true
        },
        describe: function (info) {
            var row = Ext.Component.from(info.eventTarget, component);
            info.row = row;
            info.record = row.getRecord();
        },
        proxy: {
            type: 'placeholder',
            getElement: function (info) {
                console.log('proxy: getElement');                    

                var el = Ext.getBody().createChild({
                    style: 'padding: 10px; width: 100px; border: 1px solid gray; color: red;',
                });
                el.show().update(info.record.get('description'));
                return el;
            }
        },
        // autoDestroy: false,
        listeners: {
            scope: me,
            beforedragstart: me.makeRelayer('beforedragstart'),
            dragstart: me.makeRelayer('dragstart'),
            dragmove: me.makeRelayer('dragmove'),
            dragend: me.makeRelayer('dragend')
        }
    });
},

disable: function () {
    this.source.disable();
},

enable: function () {
    this.source.enable();
},

doDestroy: function () {
    Ext.destroy(this.source);
    this.callParent();
},

makeRelayer: function (name) {
    var me = this;
    return function (source, info) {
        return me.fireEvent(name, me, info);
    };
}
});

Tree

xtype: 'tree',
    hideHeaders: true,

    plugins: {
        treedrag: {
            type: 'treedrag',
            listeners: {
                beforedragstart: function (plugin, info) {
                    console.log('listeners: beforedragstart');
                }
            }
        }
    },
    columns: [{
            xtype: 'treecolumn',
            flex: 1,
        }
    ]

Controller

afterLoadApportionmentObjectsForTree: function (succes) {
    if (succes) {

        tree = this.getView().down('tree');
        if (tree) {
            tree.expandAll();
            tree.updateHideHeaders(tree.getHideHeaders());
            var store = tree.getStore();
            store.remoteFilter = false;
            store.filterer = 'bottomup';

            this.createDropTargets();
        }
    }
},

createDropTargets: function () {
    var me = this,
        rows = tree.innerItems;
    Ext.each(rows, function (el) {
        var target = new Ext.drag.Target({
            element: el.element,
            listeners: {
                scope: me,
                drop: me.onDrop
            }
        });
    });
},

onDrop: function (target, info, eOpts) {
    var source = info.record,
        row = Ext.Component.from(target.getElement(), tree),
        destination = row.getRecord(),
        parentNode = source.parentNode;

    destination.appendChild(source);
    destination.expand();

    if (!parentNode.hasChildNodes()) {
        parentNode.set('leaf', true);
    }
}

Edit

It seems that updateInfo is called recursive, but I can't figure out why or how I could prevent it.

1条回答
萌系小妹纸
2楼-- · 2019-08-12 15:45

I could find the mistake by myself. It was possible to drag nodes on their own children which relates to an recursive adding and removing of the same nodes over and over again. To prevent the user from doing this, I added an listener for the beforeDrop event to my Ext.drag.Target. There it returns false, if the target node is the same as the source node and it returns false if the target node is a child node of the source node.

 onBeforeDrop: function (target, info, eOpts) {
    var source = info.record,
        row = Ext.Component.from(target.getElement(), tree),
        destination = row.getRecord();

    if (source == destination) {
        return false;
    }
    if (source.findChild('number', destination.get('number'), true) != null) {
        return false;
    }

    return true;
}

I also used the beforedragstart event to prevent moving the root node.

Maybe this is helpful for someone else.

查看更多
登录 后发表回答