Hybrid View

  1. #1
    Sencha User
    Join Date
    Mar 2009
    Location
    Dallas, TX
    Posts
    19
    Vote Rating
    2
    darkwolfe is on a distinguished road

      1  

    Cool New Editor Tree Grid Extension based on Ext.ux.tree.TreeGrid

    New Editor Tree Grid Extension based on Ext.ux.tree.TreeGrid


    I know this is a bit late since not many people still use ExtJS 3.4, but I thought that someone out there might be able to benefit from this. The company I work for finally decided to upgrade to ExtJS3.4 from ExtJS2.2.1. In the earlier version we used the MaximGB tree grid extension for our order system, however, the version that was compatible with 3.4 had problems. It was slow, complicated, and had a bug in the GridView that caused the formatting to screw up every time and edit was made. This meant that the GridView had to be redrawn after each edit, really slowing down grid. I needed a tree grid and the only thing out there other than MaximGB was also an extension of the GridPanel, did not work with 3.4, and was no longer going to be receiving updates. So, creating this extension was my only option.

    Now the cool thing about this extension is that it extends the Ext.ux.tree.TreeGrid class, so I didn't have to write the tree handling functions, which seemed more complicated than the grid editing function I needed.

    Like I said, this extends the tree grid ux that comes with Ext, but it also has a couple of overrides to add record like get and set functions to the Ext.tree.TreeNode class and adds some methods to the TreeGrid class that were oddly missing, such as functions that get information from the columns, like getDataIndex.

    Added Properties/Config Options:
    • cellSelector, used to find cells internally (defaults to 'td.x-treegrid-col')
    • cellSelectorDepth, the number of levels to search for cells in event delegation (defaults to 4)
    • rowSelector, used to find rows internally (defaults to 'div.x-grid3-row')
    • rowSelectorDepth, the number of levels to search for rows in event delegation (defaults to 10)
    • autoEncode, true to automatically HTML encode and decode values pre and post edit (defaults to false)
    • forceValidation, true to force validation even if the value is unmodified (defaults to false)
    • loadMask, an Ext.LoadMask config or true to mask the grid while loading. Defaults to false
    • expandOnDdlClick, when set to false, disabled the tree's double click event to stop the branch from expanding on double click. an event listener attached to the config object will still fire, however. defaults to false.
    • completeOnEnter: True to complete edit when the enter key is pressed, defaults to true
    • cancelOnEsc: True to cancel the edit when the escape key is pressed, defaults to true
    • ignoreNoChange: True to skip the edit completion process (no save, no events fired) if the user completes an edit and the value has not changed (defaults to false). Applies only to string values - edits for other data types will never be ignored.
    Added Methods:
    • startEditing, starts editing the specified for the specified row/column
    • getColumnModel, returns the tree's column config object
    • getCellEditor, returns the editor defined for the cell/column
    • setEditable, sets if a column is editable
    • stopEditing, stops any active editing
    • isCellEditable, returns true if the cell is editable
    • getDataIndex, returns the dataIndex for the specified column
    • getIndexById, returns the index for a specified column id
    • getColumnId, returns the id of the column at the specified index
    • getColumnAt, returns the column at the specified index
    • findRow, return the HtmlElement representing the tree node which contains the passed element
    • findRowIndex, return the index of the tree node which contains the passed HTMLElement
    • findRowId, return the index of the tree node which contains the passed HTMLElement
    • toString, returns an XML or JSON serialized string of the tree panel or false if Ext.tree.TreeSerializer does not exist (see explanation below), returns json by default
    • getSerializer, returns the internal serializer or false if Ext.tree.TreeSerializer does not exist (see explanation below), returns json serializer by default
    Added Event Listeners:
    • cellclick, fires when a cell is clicked
    • celldblclick, fires when a cell is double clicked
    • beforeedit, fires before cell editing is triggered
    • afteredit, fires after a cell is edited
    • validateedit, fires after a cell is edited, but before the value is set in the node
    • beforedatadrop, firex before non-node data is dropped on a tree node
    • datadrop, fires after non-node data is droped onto a tree node
    New Ext.tree.TreeNode Methods (Note: all methods compatible with standard trees):
    • set, sets values for fields in a node on the tree grid
    • get, gets values for fields in a node on the tree grid
    • setLeaf, replaces a tree branch with a leaf containing the same attributes, destroying all child nodes, pass in false to turn a leaf into a branch (usefully when creating a branch out of a leaf to add childNodes to it), returns newly created node
    • toggleLeaf, toggles leaf/branch state, when changing into a leaf destroys all child nodes, returns newly created node
    Using this new class is as easy as using the standard Ext.ux.tree.TreeGrid, all you have to do is add an editor to the column model like you would on an EditorGridPanel. Also, many of the methods and events found in an EditorGridPanel, as listed above, take/provide the same parameters, with the exception of cellclick and celldblclick, they work more like the tree's click and dblclick events.

    Extended the Ext.tree.TreeDropZone to add a new event called "datadrop" that is fired when any non-node data is dropped onto a tree node. Normally the tree's native drag and drop events do not fire when any data that does not contain a tree node is dropped, which means you have to specify a dropConfig overwriting the notifyDrop function or similar functions, potentially loosing the tree's native drag and drop functionality. This new event will only fire when the data being dropped is not a tree node.

    Ext.ux.tree.EditorGrid creates it's own internal tree serializer and defines the function 'toString()' and 'getSerializer()' if Ext.tree.TreeSerializer exists. Simply pass 'xml' or 'json' into the toString() function to get your desired output or getSerializer() to get a reference to the internal serializer. if Ext.tree.TreeSerializer does not exists, these functions will return false.

    PHP Code:
        ...
        var 
    serialized editorTreeGrid.toString('json');
        if (
    serializedconsole.log(Ext.decode(serialized));
        else 
    console.log('serializer does not exist');
        ... 
    PHP Code:
        ...
        
    datadrop: function(e) {
            
    console.info('datadrop listener');
            
    console.info('e: ',e);
        } 
    node now has set and get functions like record:
    PHP Code:
        ...
        
    listeners: {
            
    'click':function(node,e) {
                
    e.node.set('itemnum','demo value');
            }
        } 
    PHP Code:
        ...
        
    listeners: {
            
    'cellclick':function(node,e) {
                
    console.log('cellclick listener');
                
    console.log('node: ',node);
                
    console.log('tree: ',e.tree);
                
    console.log('field: ',e.field);
                
    console.log('value: ',e.value);
                
    console.log('row: ',e.row);
                
    console.log('column: ',e.column);
            }
        } 
    PHP Code:
    var treeGrid = new Ext.ux.tree.EditorGrid({
        
    //--TREE SETTINGS--//
        
    border:    false,
        
    bodyBorderfalse,
        
    animatetrue,
        
    enableDDtrue,
        
    enableSortfalse,
        
    loadMask: {msg'Loading Demo Tree Grid Data...' },

        
    //--COLUMN MODEL--//
        
    columns: [{
            
    header:'Item Name/Number',
            
    width:200,
            
    dataIndex:'itemnum',
            
    editor: new Ext.form.TextField({ selectOnFocustrue })
        },{
            
    header:'Description',
            
    width:227,
            
    dataIndex:'itemdesc',
            
    editor: new Ext.form.TextField({ selectOnFocustrue })
        },{
            
    header:'Qty',
            
    width:50,
            
    dataIndex:'defqty',
            
    editor: new Ext.form.NumberField({
                
    allowBlankfalse,
                
    allowNegativefalse,
                
    selectOnFocustrue,
                
    style'text-align:left'
            
    })
        },{
            
    header:'Price',
            
    width:60,
            
    dataIndex:'defprice',
            
    renderer'usMoney',
            
    editor: new Ext.form.NumberField({
                
    //allowBlank: false,
                
    allowNegativefalse,
                
    selectOnFocustrue,
                
    style'text-align:left'
            
    })
        }],            

        
    //--TREE LOADER--//
        
    loader: new Ext.tree.TreeLoader({
            
    urldatafile.json,
            
    preloadChildrentrue,
            
    listeners: {
                
    loadexception: function(loadernoderesponse) {
                    var 
    msg 'unable to fetch data. response.status:' response.status + (? (', error: ' e.message) : '');
                    
    Ext.Msg.alert('Demo'msg10);
                },
                
    load: function(loadernoderesponse) {
                    
    Ext.Msg.alert('Demo''Loading complete...',3);
                }
            }
        }),

        
    //--EVENT LISTENERS--//
        
    listeners: {
            
    'beforeedit': function(e) { if (e.node.isLeaf() && e.field == 'itemnum') return false; },
            
    'validateedit': function(e) {
                var 
    myTargetCol 1;

                if (
    e.column == myTargetCol && (e.value != 'option1' && e.value != 'option2')) {
                    
    e.cancel true;
                    var 
    colName e.tree.getColumnAt(e.column);
                    
    alert(colName.header+' has been set with an invalid value, please enter \'option1\' or \'option2\'');
                }
            }
        }
    }); 
    Attached Images
    Attached Files
    Last edited by darkwolfe; 8 Nov 2011 at 1:37 PM. Reason: Fixed a bug with editing and scrolling

  2. #2
    Sencha User murrah's Avatar
    Join Date
    Oct 2007
    Location
    Katoomba, Blue Mountains, west of Sydney, Australia
    Posts
    387
    Vote Rating
    11
    murrah will become famous soon enough

      0  

    Default


    Hi,

    I am still using Ext 3.4 since I am developing for AIR. I use the Ext.ux.tree.TreeGrid (with modified Template so AIR will work). At present I have no need for the editor functionality you have added (but I imagine I soon will!). Thanks for your work.

    My question is, do you know if it is possible to do multi select the grid rows? eg Shift+Click, CTRL+Click etc? I cant find a way to do this.

    Thanks,
    Murray

  3. #3
    Sencha User
    Join Date
    Mar 2009
    Location
    Dallas, TX
    Posts
    19
    Vote Rating
    2
    darkwolfe is on a distinguished road

      0  

    Default


    Quote Originally Posted by murrah View Post
    Hi,

    I am still using Ext 3.4 since I am developing for AIR. I use the Ext.ux.tree.TreeGrid (with modified Template so AIR will work). At present I have no need for the editor functionality you have added (but I imagine I soon will!). Thanks for your work.

    My question is, do you know if it is possible to do multi select the grid rows? eg Shift+Click, CTRL+Click etc? I cant find a way to do this.

    Thanks,
    Murray
    Since the TreeGrid only extends a the TreePanel, and likewise this extension extends the TreeGrid, i would imagine that you just set the selection module using the selModel config parameter. As far as i can tell, the TreeGrid doesn't alter any selection model functions.

    PHP Code:
    ...
    selMode: new Ext.tree.MultiSelectionModel(),
    ... 

  4. #4
    Sencha User murrah's Avatar
    Join Date
    Oct 2007
    Location
    Katoomba, Blue Mountains, west of Sydney, Australia
    Posts
    387
    Vote Rating
    11
    murrah will become famous soon enough

      0  

    Default


    Yes, you are correct. Adding selModel to the config adds the multi selection mode. The fact that I specified selMode instead of selModel wasnt helping! Thanks!

  5. #5
    Sencha User
    Join Date
    Aug 2009
    Posts
    2
    Vote Rating
    0
    JK. is on a distinguished road

      0  

    Thumbs up Great!

    Great!


    This is really great. I wonder if this works on extjs 4?

  6. #6
    Sencha User
    Join Date
    Mar 2009
    Location
    Dallas, TX
    Posts
    19
    Vote Rating
    2
    darkwolfe is on a distinguished road

      0  

    Default


    Thanks!

    I don't know if it works in Ext4 yet. I plan on finding out as soon as i finish up this part of the project that i'm using it for. If it doesn't i'll be converting to work in it since they still didn't put editor functionality into it.

  7. #7
    Sencha User
    Join Date
    Apr 2011
    Posts
    9
    Vote Rating
    0
    Sreekesh S K is on a distinguished road

      0  

    Default


    Is it possible to implement alternate row coloring system on this plugin

  8. #8
    Sencha User
    Join Date
    Mar 2009
    Location
    Dallas, TX
    Posts
    19
    Vote Rating
    2
    darkwolfe is on a distinguished road

      0  

    Default


    Quote Originally Posted by Sreekesh S K View Post
    Is it possible to implement alternate row coloring system on this plugin
    i realize that this reply is 2 years too late, but just in case it helps:

    I'm not sure how easily it'll be to alternate row coloring, however, you can try to hook into the beforechildrenrendered listener and add a CSS class to the node's underlying element. That should do the trick.

    I image something like the following will work:

    PHP Code:
        ...
        
    listeners: {
            
    beforechildrenrendered: function(node) {
                var 
    nodeIndex node.getOwnerTree().getRootNode.indexOf(node);
                if (
    nodeIndex 2node.ui.addClass('you-row-stripe-class');
            }
        }
        ... 
    hope that helps, though it probably won't since it's 2 years too late.

  9. #9
    Sencha User
    Join Date
    Feb 2014
    Posts
    4
    Vote Rating
    0
    garg.shivani02 is on a distinguished road

      0  

    Default


    Hi,

    Thanks darkwolfe for the reply...!!!!

    I am using Extjs 3.4 version.I also have a doubt that I am unable to use this extension which is a ux component. It would be great if you can just post a sample code to use this extension.

    Also do I also need to have the Ext.ux.tree.TreeGrid component also so as to use this extension?
    If yes can you please post some link from where I can get this compatible to your extension.

    Thanks again!

  10. #10
    Sencha User
    Join Date
    Mar 2009
    Location
    Dallas, TX
    Posts
    19
    Vote Rating
    2
    darkwolfe is on a distinguished road

      0  

    Default


    Quote Originally Posted by garg.shivani02 View Post

    I am using Extjs 3.4 version.I also have a doubt that I am unable to use this extension which is a ux component. It would be great if you can just post a sample code to use this extension.
    Below is a simple code example used in one of my projects. It uses normal JSON tree data as loaded into any normal tree, so nothing complicated.

    PHP Code:
            var contextMenu = new Ext.menu.Menu({
                
    items: [
                    { 
    name'expand-node'iconCls'icon-expand-all'text'Expand All' },
                    { 
    name'collapse-node'iconCls'icon-collapse-all'text'Collapse All' }
                ],
                
    listeners: {
                    
    beforeshow: function (menu) {
                        var 
    menu.contextNode,
                        
    items menu.items.items;
                        for (var 
    0items.lengthi++) {
                            switch (
    items[i].name) {
                                case 
    'expand-node':
                                case 
    'collapse-node':
                                    if (
    n.isLeaf()) items[i].disable();
                                    else 
    items[i].enable();
                                    break;
                            }
                        }
                    },
                    
    itemclick: function (item) {
                        var 
    item.parentMenu.contextNode;
                        switch (
    item.name) {
                            case 
    'expand-node'n.expand(true); break;
                            case 
    'collapse-node'n.collapse(true); break;
                        }
                    }
                }
            });
            
    self.groupsGrid = new Ext.ux.tree.EditorGrid({
                
    clicksToEdit:1,
                
    height185,
                
    dataUrlself.handler '?command=get:settings.groups',
                
    autoExpandColumn'actionName',
                
    enableDDfalse,
                
    loadMask: { msg'Loading Groups and Statuses...' },
                
    enableSortfalse,
                
    ignoreNoChangefalse,
                
    expandOnDblClicktrue,
                
    contextMenucontextMenu,
                
    columns: [{
                    
    header'Group/Status',
                    
    id'actionName',
                    
    width230,
                    
    dataIndex'actionName',
                }, {
                    
    header'Distribution List',
                    
    id'distro',
                    
    width150,
                    
    dataIndex'distro',
                    
    editor: new Ext.form.ComboBox({
                        
    typeAheadtrue,
                        
    triggerAction'all',
                        
    storeself.distroStore,
                        
    lazyRendertrue,
                        
    editablefalse,
                        
    displayField'name',
                        
    valueField'name',
                        
    mode'local',
                        
    listClass'x-combo-list-small'
                    
    })
                }, {
                    
    header'Email Template',
                    
    id'template',
                    
    width150,
                    
    dataIndex'template',
                    
    editor: new Ext.form.ComboBox({
                        
    typeAheadtrue,
                        
    triggerAction'all',
                        
    storeself.templateStore,
                        
    lazyRendertrue,
                        
    editablefalse,
                        
    displayField'name',
                        
    valueField'name',
                        
    mode'local',
                        
    listClass'x-combo-list-small'
                    
    })
                }],
                
    listeners: {
                    
    beforeedit: function (e) {
                        var 
    self this;
                        if (!
    e.node.isLeaf()) return false;
                        if (
    e.field == 'template') switch (e.node.get('actionName')) {
                            case 
    'Create Ticket':
                            case 
    'Close Ticket':
                                
    MyApp.notify('Warning''Cannot set <i>' e.node.get('actionName') + '</i> template.  This field is set using the combobox above.',5);
                                return 
    false;
                            case 
    'Ticket Statuses': return false; break;
                        }
                        return 
    true;
                    },
                    
    validateedit: function(e) {
                        var 
    self this;
                        return 
    true;
                    },
                    
    afteredit: function (e) {
                        var 
    self this;
                        return 
    true;
                    },
                    
    contextmenu: function (nodee) {
                        
    node.select();
                        var 
    node.getOwnerTree().contextMenu;
                        
    c.contextNode node;
                        
    c.showAt(e.getXY());
                    }
                }
            }); 
    Quote Originally Posted by garg.shivani02 View Post

    Also do I also need to have the Ext.ux.tree.TreeGrid component also so as to use this extension?
    If yes can you please post some link from where I can get this compatible to your extension.
    The Ext.ux.tree.TreeGrid is an extension that comes bundled with ExtJS 3.4. Check the /examples/treegrid folder of your ExtJS installation for example usuage and /examples/ux/treegrid for required sources.