Results 1 to 10 of 10

Thread: onNodeInsert function implementation bug

    You found a bug! We've classified it as EXTJS-19583 . We encourage you to continue the discussion and to find an acceptable workaround while we work on a permanent fix.
  1. #1
    Sencha User
    Join Date
    Oct 2014
    Posts
    20

    Default onNodeInsert function implementation bug

    Hello All,

    I'm using drag & drop functionality (with 2 tree panels).

    Each tree panel has a filtration bar and when it is not-empty drag & drop returns an error and application stucks.
    Javascript error I received is "Uncaught TypeError: Cannot read property 'isExpanded' of null".


    After digging within code, I found a problematic code within Ext.data.TreeStore onNodeInsert function
    "for (sibling = node.previousSibling;sibling && !sibling.get('visible');
    sibling = sibling.previousSibling) {}"


    I recognize problems with for loop when "node" object has exact 0-1 previousSibling - In this case "sibling" value is null. (and it causes javascript errors and application stucks)

    To solve drag&drop when filtration not-empty, I added the following code after loop:
    "
    if (sibling === null) {
    if (node.previousSibling === null) {
    sibling = node;
    }
    else {
    sibling = node.previousSibling;
    }
    }

    This code prevent "sibling" variable to become nullable. - I'm not sure it is the best solution, but, it solves severe application bugs.

    I think you (Sencha) should take care of this problematics "for" loop iterations and verify there won't be nullable value/s.

    Thanks,
    Erez

  2. #2
    Sencha - Sustaining Engineer tristan.lee's Avatar
    Join Date
    Mar 2015
    Location
    Central Ohio
    Posts
    1,579

    Default

    Thank you for reporting. Can you please provide a test case as a fiddle so I can verify this is an issue?
    Tristan Lee
    Sencha Inc - Sustaining Engineer


    Having an issue? Help us help you - be detailed; provide some code; demonstrate with a fiddle (fiddle.sencha.com)

    Embed your fiddle in your post: [FIDDLE]id[/FIDDLE]

  3. #3
    Sencha User
    Join Date
    Oct 2014
    Posts
    20

    Default

    Hi Tristan,

    Too complex for me to fiddle it.

    I think developer can view the code and understand what I said here.
    There are unhandled cases within the mentioned "for" loop. (therefore, bad scenario can happen)


    Please fix it, I think it can significantly improve ExtJS stability for some cases.

  4. #4

    Default simple bug test

    Code:
    function getActualWidth() {    var actualWidth = window.innerWidth ||
                          document.documentElement.clientWidth ||
                          document.body.clientWidth ||
                          document.body.offsetWidth;
    
    
        return actualWidth;
    }
    
    
    function getActualHeight() {
        var actualWidth = window.innerHeight ||
                          document.documentElement.clientHeight ||
                          document.body.clientHeight ||
                          document.body.offsetHeight;
    
    
        return actualWidth;
    }
    
    
    window.onload = function () {
    
    
        var store1 = Ext.create('Ext.data.TreeStore', {
            storeId: 'store1',
            root: {
                expanded: true,
                children: [
                    { id: 1, text: '1', leaf: true },
                { id: 2, text: '2', leaf: true },
                { id: 3, text: '3', leaf: true },
                { id: 4, text: '4', leaf: true },
                { id: 5, text: '5', leaf: true },
                { id: 6, text: '6', leaf: true },
                { id: 7, text: '7', leaf: true },
                { id: 8, text: '8', leaf: true },
                { id: 9, text: '9', leaf: true },
                { id: 10, text: '10', leaf: true },
                ]
            }
        });
    
    
        var store2 = Ext.create('Ext.data.TreeStore', {
            storeId: 'store2',
            root: {
                expanded: true,
                children: [
                    { id: 1, text: '1', leaf: true },
                { id: 2, text: '2', leaf: true },
                { id: 3, text: '3', leaf: true },
                { id: 4, text: '4', leaf: true },
                { id: 5, text: '5', leaf: true },
                { id: 6, text: '6', leaf: true },
                { id: 7, text: '7', leaf: true },
                { id: 8, text: '8', leaf: true },
                { id: 9, text: '9', leaf: true },
                { id: 10, text: '10', leaf: true },
                ]
            }
        });
    
    
        var treePanel1 = Ext.create('Ext.tree.Panel', {
            title: 'Title1',
            //    width: 200,
            flex:1,
            store: store1,
            lines: false,
            rootVisible: false,
        });
    
    
        var treePanel2 = Ext.create('Ext.tree.Panel', {
            title: 'Title2',
            //    width: 200,
            flex: 1,
            store: store2,
            lines: false,
            rootVisible: false,
        });
    
    
        var MainPanel = Ext.create('Ext.panel.Panel', {
            title: '2222',
            width: getActualWidth(),
            height: getActualHeight(),
            layout: {
                type: 'hbox',
                align: 'stretch'
                //width: 500
            },
    
    
            border: true,
            //margin: '0 5 0 0',
            items: [
                treePanel1, {
                    xtype: 'splitter',
                },
                treePanel2
            ],
            renderTo: Ext.getBody()
        });
    
    
    
    
    
    
    
    
        Ext.on('resize',
            function (w, h) {
                //console.log('size=(' + w + ', ' + h + ')');
                MainPanel.setSize(w, h);
            }
        );
    
    
        setInterval(function () {
    
    
            var mas1 = [
                { id: 1, text: '1', leaf: true },
                { id: 2, text: '2', leaf: true },
                { id: 3, text: '3', leaf: true },
                { id: 4, text: '4', leaf: true },
                { id: 5, text: '5', leaf: true },
                { id: 6, text: '6', leaf: true },
                { id: 7, text: '7', leaf: true },
                { id: 8, text: '8', leaf: true },
                { id: 9, text: '9', leaf: true },
                { id: 10, text: '10', leaf: true },
            ];
    
    
            var Available1 = [1, 7];
    
    
            store1.setRoot({
                expanded: true,
                children: mas1
            });
    
    
            store1.clearFilter();
            store1.filterBy(function (rec) {
    
    
                var ok = $.inArray(rec.data.id, Available1) > -1;
    
    
                return ok;
            });
    
    
            var mas2 = [
                { id: 1, text: '1', leaf: true },
                { id: 2, text: '2', leaf: true },
                { id: 3, text: '3', leaf: true },
                { id: 4, text: '4', leaf: true },
                { id: 5, text: '5', leaf: true },
                { id: 6, text: '6', leaf: true },
                { id: 7, text: '7', leaf: true },
                { id: 8, text: '8', leaf: true },
                { id: 9, text: '9', leaf: true },
                { id: 10, text: '10', leaf: true },
            ];
    
    
            var Available2 = [3, 8];
    
    
            store2.setRoot({
                expanded: true,
                children: mas2
            });
    
    
            store2.clearFilter();
            store2.filterBy(function (rec) {
    
    
                var ok = $.inArray(rec.data.id, Available2) > -1;
    
    
                return ok;
            });
    
    
    
    
        }, 1000);
    
    
    
    
    };
    Bug on 5.x and 6.0 version extjs

  5. #5
    Sencha User
    Join Date
    Oct 2014
    Posts
    20

    Default

    Thanks, but, I don't see how it is related at all to the bug I mentioned.

    It's hard for me to reproduce issue within fiddler, however, I expect someone from Sencha developer (or other developer) to see the bug within code.

    If Sencha can see bug within code, I think it should be enough to take over and fix it.

    Until now, I couldn't see any real response for this issue, although it defects application severely.

  6. #6

    Default

    It is the same problem.

    We both use 2 tree.Panel and 2 data.TreeStore.
    We both use filters.
    We both get the same error codes.
    I checked - for one data.TreeStore problem does not occur.
    We both have a error in the same place - a function onNodeInsert, location:
    Code:
     // Find the previous visible sibling (filtering may have knocked out intervening nodes)
                    for (sibling = node.previousSibling; sibling && !sibling.get('visible'); sibling = sibling.previousSibling) {}
                    // empty
                    while (sibling.isExpanded() && sibling.lastChild) {
                        sibling = sibling.lastChild;
    But i cannot modify original sencha code.

  7. #7

    Default

    And problem not closed in 6.0

  8. #8
    Sencha User
    Join Date
    Oct 2014
    Posts
    20

    Default

    Yes, it causes severe bugs.

    I hope Sencha won't keep ignores this one. (maybe you can message Tristan from Sencha to proceed this).

    However, I will send you a code with my fix (override of this function), so you can use (it fits to ExtJS 5.11, but take a look at my fix within code if you use different version and it fix your issue for most cases):

    "

    Ext.override(Ext.data.TreeStore, { // Use it to avoid "Uncaught TypeError: Cannot read property 'isExpanded' of null" bug.

    /**
    * @private
    *
    * Called from a node's insertBefore method.
    *
    * This function overriden reason is to solve most of filtration drag & drop Extjs errors when filtration is not empty.
    * My fix - fix scenario when there is 0-1 node previousSibling.
    *
    */
    onNodeInsert: function(parent, node, index) {
    var me = this,
    data = node.raw || node.data,
    refNode,
    sibling,
    storeReader,
    nodeProxy,
    nodeReader,
    reader,
    dataRoot;


    if (parent && me.needsLocalFilter()) {
    me.doFilter(parent);
    }


    me.beginUpdate();


    // Only react to a node append if it is to a node which is expanded.
    if (me.isVisible(node)) {
    if (index === 0 || !node.previousSibling) {
    refNode = parent;
    } else {
    // Find the previous visible sibling (filtering may have knocked out intervening nodes)
    for (sibling = node.previousSibling;
    sibling && !sibling.get('visible');
    sibling = sibling.previousSibling) {
    // empty
    }



    if (sibling === null) { // My fix - fix scenario when there is 0-1 node previousSibling.
    if (node.previousSibling === null) {
    //console.log('bug was fixed (#1)');
    sibling = node;
    }
    else {
    //console.log('bug was fixed (#2)');
    sibling = node.previousSibling;
    }

    //console.log(node);
    //console.log(node.previousSibling);
    }




    while (sibling.isExpanded() && sibling.lastChild) {
    sibling = sibling.lastChild;
    }
    refNode = sibling;
    }


    // The reaction to collection add joins the node to this Store
    me.insert(me.indexOf(refNode) + 1, node);
    if (!node.isLeaf() && node.isExpanded()) {
    if (node.isLoaded()) {
    // Take a shortcut
    me.onNodeExpand(node, node.childNodes);
    } else if (!me.fillCount) {
    // If the node has been marked as expanded, it means the children
    // should be provided as part of the raw data. If we're filling the nodes,
    // the children may not have been loaded yet, so only do this if we're
    // not in the middle of populating the nodes.
    node.set('expanded', false);
    node.expand();
    }
    }
    }


    // New nodes mean we need a sync if those nodes are phantom or dirty (have client-side only information)
    me.needsSync = me.needsSync || node.phantom || node.dirty;


    if (!node.isLeaf() && !node.isLoaded() && !me.lazyFill) {
    // With heterogeneous nodes, different levels may require differently configured readers to extract children.
    // For example a "Disk" node type may configure it's proxy reader with root: 'folders', while a "Folder" node type
    // might configure its proxy reader with root: 'files'. Or the root property could be a configured-in accessor.
    storeReader = me.getProxy().getReader();
    nodeProxy = node.getProxy();
    nodeReader = nodeProxy ? nodeProxy.getReader() : null;


    // If the node's reader was configured with a special root (property name which defines the children array) use that.
    reader = nodeReader && nodeReader.initialConfig.rootProperty ? nodeReader : storeReader;


    dataRoot = reader.getRoot(data);
    if (dataRoot) {
    me.fillNode(node, reader.extractData(dataRoot, {
    model: node.childType,
    recordCreator : me.recordCreator
    }));
    }
    }
    me.endUpdate();
    },

    });

    "

  9. #9
    Sencha - Sustaining Engineer tristan.lee's Avatar
    Join Date
    Mar 2015
    Location
    Central Ohio
    Posts
    1,579

    Default

    I created a smaller example fiddle of this to demonstrate the issue. I'm working with the engineers to see how this should be classified.

    Tristan Lee
    Sencha Inc - Sustaining Engineer


    Having an issue? Help us help you - be detailed; provide some code; demonstrate with a fiddle (fiddle.sencha.com)

    Embed your fiddle in your post: [FIDDLE]id[/FIDDLE]

  10. #10
    Sencha Premium User
    Join Date
    Sep 2011
    Location
    Tamworth, NSW, Australia
    Posts
    1,307

    Default

    I'm getting this error on line 266 of ViewDropZone.js in Ext JS 6.2.0. If I drag and drop a node to move it, it hangs on this line. Refresh the parent node and I can see that the move did actually work, but it's choking on targetNode being null on this particular line. No, I do not have a Fiddle :-)

    Edit: I have reproduced it in a Fiddle for 6.2.0 here.

Similar Threads

  1. Replies: 2
    Last Post: 4 Mar 2015, 12:54 PM
  2. Tab Panel Implementation?
    By Ukonxix in forum Sencha Touch 2.x: Q&A
    Replies: 2
    Last Post: 2 Jul 2014, 4:23 PM
  3. Desktop Implementation
    By army81 in forum Sencha GXT Q&A
    Replies: 6
    Last Post: 13 Aug 2013, 1:31 PM
  4. carousel implementation
    By v0nni in forum Sencha Architect 2.x: Help & Discussions
    Replies: 3
    Last Post: 8 Jun 2012, 7:02 AM
  5. EXT CRM implementation
    By lokshu in forum Community Discussion
    Replies: 6
    Last Post: 27 Oct 2008, 8:46 PM

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •