ExtJS 4.1 treepanel - expanding a treepanel is resulting in duplicate records
Asked Answered
C

2

6

I am using ExtJS 4.1. I have a TreePanel which I bind to one of two TreeStore. After I rebind a store & expand collapse nodes, records are getting duplicate & I see error Uncaught TypeError: Cannot read property 'internalId' of undefined

Another issue is, I am only able to bind store once. When i call treePanel.setRootNode() second time it does not work (irrespective of whether I expand the nodes or not).

Look at this fiddle

Here is the code:

var sportsStore = Ext.create('Ext.data.TreeStore', {
  root: {
    expanded: true,
    id: 133,
    children: [{
        text: "Audi",
        id: 1,
        leaf: true
      },
      {
        text: "sports cars",
        expanded: true,
        id: 2,
        children: [{
            id: 3,
            text: "Porsche",
            leaf: true
          },
          {
            text: "Mustang",
            id: 4,
            leaf: true
          }
        ]
      },
      {
        text: "Jaguar",
        id: 5,
        leaf: true
      }
    ]
  }
});


var carStore = Ext.create('Ext.data.TreeStore', {
  root: {
    expanded: true,
    id: 1444,
    children: [{
        id: 6,
        text: "Toyota",
        leaf: true
      },
      {
        text: "cars",
        id: 7,
        expanded: true,
        children: [{
            id: 8,
            text: "honda",
            leaf: true
          },
          {
            text: "Nissan",
            id: 9,
            leaf: true
          }
        ]
      },
      {
        text: "Kia",
        id: 10,
        leaf: true
      }
    ]
  }
});



Ext.create('Ext.panel.Panel', {
  title: 'Car Simple Tree',
  width: 300,
  height: 450,

  renderTo: Ext.getBody(),

  items: [{
      xtype: 'button',
      text: 'sports',
      handler: function() {
        alert('You clicked the sports button!');
        var t = Ext.getCmp('tp');

        t.setRootNode(sportsStore.getRootNode());
      }
    },

    {
      xtype: 'button',
      text: 'car',
      handler: function() {
        alert('You clicked the car button!');
        var t = Ext.getCmp('tp');

        t.setRootNode(carStore.getRootNode());
      }
    },
    {

      xtype: 'treepanel',
      id: 'tp',
      store: sportsStore,
      rootVisible: false,
      lines: true
    }
  ]


});
Convulsion answered 22/7, 2018 at 13:27 Comment(5)
Check that FIDDLE this will help you.Retroflexion
@NarendraJadhav: You are not using store in this case. when we use store, we run into this issue.Convulsion
@Convulsion ware you able to see if the answer I had bellow helps?Premedical
@Akrion: it is working. But its a hacky way to achieve the desired result. Let's see if we get more answers in next two days (which I doubt).Convulsion
@Convulsion hey no rush. Just was wondering if you have a chance to see it and your opinion on the result. As I said it might not be your cup of tea :). Earlier version of Sencha as far as I remember had plenty of stuff like these where hacks ware pretty much required. I would love to see an actual solution without re-create as well.Premedical
P
1

Just for the record you know your problem is solved in one line in 6.0 with just calling setStore() and passing as parameter the store you want right?

Here is a demo of this working in 6.0.

I played with this for a good amount of time and although my Sencha is somewhat rusty (used to be a big fan back in the day) I managed to get something working.

Now it might not be your cup of tea but it does exactly what you want ... you change the stores and expanding/collapsing works etc. The trick is I dynamically re-create the tree on every store change and set the store as the default store to that new tree. The decommissioned trees are removed by Ext.destroy etc.

Here is that Ext 4.1 working example in Fiddle

And here is the code for your reference:

Ext.define('Thing', {
  extend: 'Ext.data.Model',
  fields: [{
    name: 'id',
    type: 'int'
  }, {
    name: 'text',
    type: 'string'
  }]
});

var sportsStore = Ext.create('Ext.data.TreeStore', {
  model: 'Thing',
  storeId: 'sportsStore',
  clearOnLoad: true,
  root: {
    expanded: true,
    id: 133,
    children: [{
      text: "Audi",
      id: 1,
      leaf: true
    }, {
      text: "sports cars",
      expanded: true,
      id: 2,
      children: [{
        id: 3,
        text: "Porsche",
        leaf: true
      }, {
        text: "Mustang",
        id: 4,
        leaf: true
      }]
    }, {
      text: "Jaguar",
      id: 5,
      leaf: true
    }]
  }
});
var carStore = Ext.create('Ext.data.TreeStore', {
  model: 'Thing',
  storeId: 'carStore',
  clearOnLoad: true,
  root: {
    expanded: true,
    id: 1444,
    children: [{
      id: 6,
      text: "Toyota",
      leaf: true
    }, {
      text: "cars",
      id: 7,
      expanded: true,
      children: [{
        id: 8,
        text: "honda",
        leaf: true
      }, {
        text: "Nissan",
        id: 9,
        leaf: true
      }]
    }, {
      text: "Kia",
      id: 10,
      leaf: true
    }]
  }
});
// This function does the magic by removing/then destroying the old tree and 
// adding the newly created one with default new store setup
function setupTree(storeName) {
  var pnl = Ext.getCmp('pnl');
  var treePanel = Ext.getCmp('tp')
  if (treePanel) {
    pnl.remove(treePanel)
    Ext.destroy(treePanel)
  }
  pnl.add(new Ext.create('Ext.tree.Panel', {
    id: 'tp',
    autoRender: true,
    rootVisible: false,
    store: storeName,
    animate: false,
    lines: true
  }))
}

Ext.create('Ext.panel.Panel', {
  id: 'pnl',
  title: 'Car Simple Tree',
  width: 300,
  height: 450,
  renderTo: Ext.getBody('#canvas'),
  items: [{
    xtype: 'button',
    text: 'sports',
    handler: function() {
      setupTree('sportsStore')
    }
  }, {
    xtype: 'button',
    text: 'car',
    handler: function() {
      setupTree('carStore')
    }
  }],
  listeners: {
    afterrender: function(self) {
      setupTree('sportsStore')
    }
  }
});

I also added ids to the stored as well as defined a model for the stores just to be more close to best practices etc.

The thing that makes this move is the setupTree function which looks for a tree with certain id, if it finds it cleans it and then creates a new one with a default store the one we clicked on.

Hope this helps.

Premedical answered 11/8, 2018 at 6:20 Comment(0)
P
0

I suggest the following approach, which may be a workaround, but ExtJS 4.1 version has some issues in UpdateIndexes() method:

  • define an empty tree store (baseStore) and bind it to the tree panel
  • on every button click, fill this empty store with data from appropriate store.

Code:

Ext.onReady(function(){

        Ext.QuickTips.init();
        Ext.FocusManager.enable();

        // Stores
        var baseStore = Ext.create('Ext.data.TreeStore', {
            root: {
                expanded: true,
                leaf: false,
                children: []
            }
        });
        var sportsStore = Ext.create('Ext.data.TreeStore', {
            root: {
            expanded: true,
            id: 133,
            children: [
            {
                text: "Audi",
                id: 1,
                leaf: true
                },
                {
                text: "sports cars",
                expanded: true,
                id: 2,
                children: [{
                    id: 3,
                    text: "Porsche",
                    leaf: true
                    },
                    {
                    text: "Mustang",
                    id: 4,
                    leaf: true
                    }
                ]
                },
                {
                text: "Jaguar",
                id: 5,
                leaf: true
                }
            ]
            }
        });
        var carStore = Ext.create('Ext.data.TreeStore', {
            root: {
            expanded: true,
            id: 1444,
            children: [
                {
                id: 6,
                text: "Toyota",
                leaf: true
                },
                {
                text: "cars",
                id: 7,
                expanded: true,
                children: [
                    {
                    id: 8,
                    text: "honda",
                    leaf: true
                    },
                    {
                    text: "Nissan",
                    id: 9,
                    leaf: true
                    }
                ]
                },
                {
                text: "Kia",
                id: 10,
                leaf: true
                }
            ]
            }
        });                 

        // Filling data
        function fillStore(xparent, xnode) {
            for (var i = 0; i < xnode.childNodes.length; i++) {
                var current = xnode.childNodes[i];
                var added = xparent.appendChild(
                    {
                    text: current.data.text,
                    leaf: current.data.leaf,
                    id: current.data.id
                    }
                );
                if (current.data.leaf === false) {
                    fillStore(added, current);
                }
            }
        }
        function setStore(store) {
            var root = baseStore.getRootNode();

            if (root.hasChildNodes()) {
                root.removeAll();
            }
            fillStore(root, store.getRootNode());
        }

        // First fill
        setStore(carStore);

    Ext.create('Ext.panel.Panel', {
        title: 'Car Simple Tree',
        width: 300,
        height: 450,

        renderTo: Ext.getBody(),

        items: [
            {
            xtype: 'button',
            text: 'sports',
            handler: function() {
                alert('You clicked the sports button!');
                var t = Ext.getCmp('tp');

                setStore(sportsStore);
            }
            },
            {
            xtype: 'button',
            text: 'car',
            handler: function() {
                alert('You clicked the car button!');
                var t = Ext.getCmp('tp');

                setStore(carStore);
                }
            },
            {
            xtype: 'treepanel',
            id: 'tp',
            store: baseStore,
            rootVisible: false,
            lines: true
            }
        ]
    });
});

Notes:

Working fiddle can be found here.

Percipient answered 14/8, 2018 at 13:52 Comment(1)
This is great. Only issue is, the model that I bind to my store has 15+ properties. and in some cases I have close to 300 nodes. In my case fillStore() will get long. I also need to evaluate the performance.Convulsion

© 2022 - 2024 — McMap. All rights reserved.