1. #21
    Ext User
    Join Date
    Apr 2008
    Posts
    1
    Vote Rating
    0
    May is on a distinguished road

      0  

    Default


    The example looks really great! Thanks for posting it up.

    Does anyone know how you can make some columns hidden?
    Thanks in advance

  2. #22
    Ext User
    Join Date
    Nov 2007
    Location
    Slovenia
    Posts
    9
    Vote Rating
    0
    Deramo is on a distinguished road

      0  

    Default Thnx

    Thnx


    works great.. thnx

  3. #23
    Sencha User
    Join Date
    Mar 2008
    Posts
    566
    Vote Rating
    0
    moegal is on a distinguished road

      0  

    Default


    How can I get parentNode?

    I am trying to return the parentNode in treeSerializer.js. It works fine in FireFox but not in Internet Explorer.

    In FireFox I get [Node ynode-480] (or what ever the node id is)
    In IE I get [object Object]

    Just learning, so please excuse my ignorance.

    I am doing the following right after you added the id attribute to the output:

    Code:
    result += ',"parentid":' + '"' + this.parentNode + '"';
    thanks,

    Marty

  4. #24
    Sencha User
    Join Date
    Apr 2007
    Location
    Italy/UK
    Posts
    152
    Vote Rating
    0
    sj137 is on a distinguished road

      0  

    Default


    i think you mean to add:

    Code:
    result += ',"parentid":' + '"' + this.parentNode.id + '"';
    or possibly

    Code:
    result += ',"parentid":' + '"' + this.parentNode.attributes.id + '"';
    hope that helps

  5. #25
    Sencha User
    Join Date
    Mar 2008
    Posts
    566
    Vote Rating
    0
    moegal is on a distinguished road

      0  

    Default


    thanks, but neither works. In both cases I get:

    "this.parentNode has no properties"

    Seems I cannot get any of the public properties directly in IE, they all show as [object Object].

    I have tried dozens of combinations, I am sure it is something simple I am missing.
    I appreciate your help anyway.

    thanks, Marty

  6. #26
    Ext JS Premium Member NoahK17's Avatar
    Join Date
    Apr 2008
    Location
    Atlanta, GA
    Posts
    518
    Vote Rating
    1
    NoahK17 is on a distinguished road

      0  

    Default


    This is a great mod... but here is what I am also trying to do:

    I want to select multiple rows at once, click or double click or right click on one of the selected fields, type in a new value, then have it push that edit across all the selected fields at once. Does that make sense?

    I'm sure I can figure it out given some time, but any insight in the meantime would be perfect
    Noah
    Senior Web Developer
    NBA.com

  7. #27
    Ext JS Premium Member NoahK17's Avatar
    Join Date
    Apr 2008
    Location
    Atlanta, GA
    Posts
    518
    Vote Rating
    1
    NoahK17 is on a distinguished road

      0  

    Default


    Alright, here's the code I used to accomplish what I described in the previous post:

    First, set up a multi selection model in your ColumnTree config:
    Code:
    selModel: new Ext.tree.MultiSelectionModel()
    Now, we want to edit the updateNode fn located under this mod's ColumnTreeEditor extension:

    Code:
        updateNode : function(ed, value){
            this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
    
            // Store the columnIndex name to a variable
            var colIndex = this.editColIndex;
            // Cascade through the tree, and edit the values of all selected nodes
            this.tree.root.cascade(function(n){
                if(n.isSelected()){
                    // Save the current value first
                    n.attributes[colIndex+'_old'] = n.attributes[colIndex];
                    // If a node is selected, edit the value
                    n.cols[colIndex] = value;
                    n.attributes[colIndex] = value;
                    
                }
            });
            
            // Update the "clicked" value
            this.editNode.cols[this.editColIndex] = value; //for internal use only
            this.editNode.attributes[this.editColIndex] = value;//duplicate into array of node attributes
            this.editCol.innerHTML = value;        
            
            // Quick method to refresh the treePanel view with the updated values. 
            this.tree.root.reload(); 
            this.tree.expandAll();
        },
    Now, I use the tree.root.reload() and expandAll() method, because I couldn't figure out, for the life of me, how to update the innerHTML of all the selected nodes, and not just the node you are currently editing.

    The _old attribute is used for an undo function, which would ideally allow you to reset everything back to what it started with before you edited anything.

    Anyhoo, this works great for static AsyncTree data, but we run into an issue with the reload() command when we pull JSON/XML data from an external source via the treeLoader.

    If anyone has any advice on the issue, I'm all ears!

    Cheers
    Noah
    Senior Web Developer
    NBA.com

  8. #28
    Ext JS Premium Member NoahK17's Avatar
    Join Date
    Apr 2008
    Location
    Atlanta, GA
    Posts
    518
    Vote Rating
    1
    NoahK17 is on a distinguished road

      0  

    Default


    Quote Originally Posted by astorne View Post
    Code:
    		var colIndex = 0;
    		for (var i in node.cols) {
    			if (node.cols[i] == obj.innerHTML) {
    				colIndex = i;
    			}
    		}
    these codes to verify which column is to be edited , but it return error column(the last column) when some columns have the same content( for example: blank string value)?
    Bug confirmed. If two or more columns have the same value, the wrong column index is returned. Working on a fix now...
    Noah
    Senior Web Developer
    NBA.com

  9. #29
    Ext User
    Join Date
    Dec 2007
    Posts
    34
    Vote Rating
    0
    DhakouaniM is on a distinguished road

      0  

    Thumbs up A little correction...

    A little correction...


    In the definition of 'Ext.tree.ColumnTreeEditor = function...', I think it'd be better to replace
    Code:
    Ext.tree.TreeEditor.superclass.constructor.call(this, field);
    with
    Code:
    Ext.tree.ColumnTreeEditor.superclass.constructor.call(this, field);
    The result is the same... but just in case someone makes further changes...

    Mehdi

  10. #30
    Ext User
    Join Date
    Dec 2007
    Posts
    34
    Vote Rating
    0
    DhakouaniM is on a distinguished road

      0  

    Smile Forbidden edit columns and Async edition

    Forbidden edit columns and Async edition


    [Rev 2 - 2008-11-10 - 19:08GMT+1]
    Here's another version with a child class with some more options and the editable column detection bug corrected...

    Call it using:
    Code:
    var te = new Ext.tree.ColumnTreeEditor(mytree, config);
    with config =
    Code:
    {
     field: (either an object containing field config and xtype - or - an Ext.form.Field descendant),
     noEditColumns: (an array containing the ids of the columns which should not be editable)
    }
    If 'field' is not provided, a default Ext.form.TextField will be used.
    If 'noEditColumns' is not provided, all columns will be editable.
    If 'config' is not provided, both above-described default values will be used.

    Code:
    Ext.tree.ColumnTree = Ext.extend(Ext.tree.TreePanel, {
      lines       : false,
      borderWidth : Ext.isBorderBox ? 0 : 2, // the combined left/right border for each cell
      cls         : 'x-column-tree',
      collapsible : false,
      
      onRender    : function() {
                      Ext.tree.ColumnTree.superclass.onRender.apply(this, arguments);
                      this.headers = this.body.createChild(
                        { cls : 'x-tree-headers' },
                        this.innerCt.dom
                      );
                      
                      var cols = this.columns, c;
                      var totalWidth = 0;
                      
                      for (var i = 0, len = cols.length; i < len; i++) {
                        c = cols[i];
                        totalWidth += c.width;
                        this.headers.createChild({
                          cls   : 'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
                          cn    : {
                                    cls   : 'x-tree-hd-text',
                                    html  : c.header
                                  },
                          style : 'width:'+(c.width-this.borderWidth)+'px;'
                        });
                      }
                      this.headers.createChild({cls:'x-clear'});
                      // prevent floats from wrapping when clipped
                      this.headers.setWidth(totalWidth);
                      this.innerCt.setWidth(totalWidth);
                    }
    });
    
    
    Ext.tree.ColumnNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
      focus : Ext.emptyFn, // prevent odd scrolling behavior
    
      renderElements  : function(n, a, targetNode, bulkRender) {
                          this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
                          
                          var t = n.getOwnerTree();
                          var cols = t.columns;
                          var bw = t.borderWidth;
                          var c = cols[0];
                          
                          n.cols = [];
                          
                          var text = n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]);
                          n.cols[n.cols.length] = cols[0].dataIndex;
                          
                          var buf = [
                            '<li class="x-tree-node" unselectable="on">',
                              '<div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf ', a.cls,'" unselectable="on">',
                                '<div class="x-tree-col" style="width:',c.width-bw,'px;" unselectable="on">',
                                  '<span class="x-tree-node-indent" unselectable="on">',this.indentMarkup,"</span>",
                                  '<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow" unselectable="on" />',
                                  '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),
                                    (a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
                                  '<a hidefocus="on" class="x-tree-node-anchor" href="',a.href ? a.href : "#",'" tabIndex="1" ',
                                    a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", ' unselectable="on">',
                                    '<span unselectable="on">', text,"</span>",
                                  "</a>",
                                "</div>"
                          ];
                          for(var i = 1, len = cols.length; i < len; i++) {
                            c = cols[i];
                            var text = (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]);
                            n.cols[n.cols.length] = cols[i].dataIndex;
                            buf.push(
                              '<div class="x-tree-col ',(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;" unselectable="on">',
                                '<div class="x-tree-col-text" unselectable="on">',text,"</div>",
                              '</div>'
                            );
                          }
                          buf.push(
                              '<div class="x-clear" unselectable="on"></div></div>',
                              '<ul class="x-tree-node-ct" style="display:none;" unselectable="on"></ul>',
                            '</li>'
                          );
                          
                          if (bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()) {
                            this.wrap = Ext.DomHelper.insertHtml("beforeBegin",
                            n.nextSibling.ui.getEl(), buf.join(""));
                          } else
                            this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
                          
                          this.elNode = this.wrap.childNodes[0];
                          this.ctNode = this.wrap.childNodes[1];
                          var cs = this.elNode.firstChild.childNodes;
                          this.indentNode = cs[0];
                          this.ecNode = cs[1];
                          this.iconNode = cs[2];
                          this.anchor = cs[3];
                          this.textNode = cs[3].firstChild;
                        }
    });
    
    Ext.tree.ColumnTreeEditor = Ext.extend(Ext.Editor, {
      alignment : 'l-l',
      autoSize  : false,
      hideEl    : false,
      cls       : 'x-small-editor x-tree-editor',
      shim      : false,
      shadow    : 'frame',
      maxWidth  : 250,
      editDelay : 350,
      
      constructor     : function(tree, config) {
                          if (!config)
                            config = {};
                          this.noEditColumns = config.noEditColumns || [];
                          var field =
                            config.field ?
                              (config.field.xtype ?
                                Ext.ComponentMgr.create(config.field) :
                                config.field) :
                              new Ext.form.TextField({
                                completeOnEnter : true,
                                autosize        : true,
                                ignoreNoChange  : true
                              });
                          Ext.tree.ColumnTreeEditor.superclass.constructor.apply(this, [field, config.editorConfig || {}]);
                          
                          this.tree = tree;
                          
                          if (!tree.rendered)
                            tree.on('render', this.initEditor, this);
                          else
                            this.initEditor(tree);
                          
                        },
      initEditor      : function(tree){
                          tree.on('beforeclick', this.beforeNodeClick, this);
                          this.on('complete', this.updateNode, this);
                          this.on('beforestartedit', this.fitToTree, this);
                          this.on('startedit', this.bindScroll, this, {delay:10});
                          this.on('specialkey', this.onSpecialKey, this);
                        },
      fitToTree       : function(ed, el){
                          var td = this.tree.getTreeEl().dom, nd = el.dom;
                          if(td.scrollLeft >  nd.offsetLeft)
                            td.scrollLeft = nd.offsetLeft;
                          var w = Math.min(
                            this.maxWidth,
                            (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - 5
                          );
                          this.setSize(w, '');
                        },
      triggerEdit     : function(node, e) {
                          this.completeEdit();
                      		if (node.attributes.editable == false)
                      		  return;
                          var obj = e.target;
                          if (Ext.select(".x-tree-node-anchor", false, obj).getCount() == 1)
                            obj = Ext.select(".x-tree-node-anchor", false, obj).elements[0].firstChild;
                          else if (obj.nodeName == 'SPAN' || obj.nodeName == 'DIV')
                            obj = e.target;
                          else
                            return false;
                          
                          var colId = -1;
                          var cols = Ext.DomQuery.select("div[@class='x-tree-col']", node.getUI().getEl().firstChild);
                          for (var i = 0 ; i < node.cols.length ; i++) {
                            if (Ext.DomQuery.select("*[@id='"+obj.id+"']", cols[i]).length == 1) {
                              colId = node.cols[i];
                              break;
                            }
                          }
                          this.editNode = node;
                          this.editCol = obj;
                          this.editColIndex = colId;
                          if (this.editColIndex == -1 || this.noEditColumns.indexOf(this.editColIndex) != -1)
                            return;
                          
                          this.autoEditTimer = (function(obj) {
                            this.startEdit(obj);
                            if (obj.nodeName == 'DIV') {
                              var width = obj.offsetWidth;
                              this.setSize(width);
                            }
                          }).defer(this.editDelay, this, [obj]);
                          return false;
                        },
      bindScroll      : function() {
                          this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
                        },
      beforeNodeClick : function(node, e){
                          var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
                          this.lastClick = new Date();
                          if (sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)) {
                            e.stopEvent();
                            this.triggerEdit(node, e);
                            return false;
                          } else
                            this.completeEdit();
                        },
      updateNode      : function(ed, value) {
                          this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
                          this.editNode.cols[this.editColIndex] = value;        //for internal use only
                          this.editNode.attributes[this.editColIndex] = value;  //duplicate into array of node attributes
                          this.editCol.innerHTML = value;
                        },
      onHide          : function() {
                          Ext.tree.TreeEditor.superclass.onHide.call(this);
                          if (this.editNode)
                            this.editNode.ui.focus();
                        },
      onSpecialKey    : function(field, e) {
                          var k = e.getKey();
                          if (k == e.ESC) {
                            e.stopEvent();
                            this.cancelEdit();
                          } else if (k == e.ENTER && !e.hasModifier()) {
                            e.stopEvent();
                            this.completeEdit();
                          }
                        }
    });
    and for the asynchronous version, which relies on the above class, use:
    Code:
    var te = new Ext.tree.AsyncColumnTreeEditor(tree, config);
    with config =
    Code:
    {
     field: (either an object containing field config and xtype - or - an Ext.form.Field descendant),
     noEditColumns: (an array containing the ids of the columns which should not be editable),
     ajaxParams: (an object containing the Ext.Ajax.request() config params to which the 'field' [column identifier], 'value' [new proposed value for the field] and 'id' [id of the edited node] fields will be appended)
    Note that you can add two listeners on this object:
    - 'nodeupdatesuccess': which will be called once the value has been confirmed by the server with a JSON response where root 'success' parameter = true,
    - 'nodeupdatefailure': which will be called once the value has been rejected by the server either with a JSON response where root 'success' parameter = false, or with a JSON failure, once the clent-side value has been reset to its original value.

    Code:
    Ext.tree.AsyncColumnTreeEditor = Ext.extend(Ext.tree.ColumnTreeEditor, {
      constructor         : function(tree, config) {
                              this.ajaxParams = {};
                              if (config.ajaxParams) {
                                this.ajaxParams = config.ajaxParams;
                                delete config.ajaxParams;
                              }
                              Ext.tree.AsyncColumnTreeEditor.superclass.constructor.apply(this, arguments);
                            },
      initComponent       : function() {
                              Ext.tree.AsyncColumnTreeEditor.superclass.initComponent.apply(this);
                              this.addEvents(
                                'nodeupdatesuccess',
                                'nodeupdatefailure'
                              );
                            },
      initEditor          : function(tree) {
                              Ext.tree.AsyncColumnTreeEditor.superclass.initEditor.apply(this, arguments);
                              this.un('complete', this.updateNode, this);
                              this.on('complete', this.beforeNodeUpdate, this);
                            },
      beforeNodeUpdate    : function(ed, newval, oldval) {
                              this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
                              if (newval == oldval)
                                return;
                              Ext.apply(this.ajaxParams.params, {
                                id    : this.editNode.id,
                                field : this.editColIndex,
                                value : newval
                              });
                              Ext.Ajax.request(
                                Ext.apply(this.ajaxParams, {
                                  success : function(response, options) {
                                              var result = Ext.decode(response.responseText);
                                              if (result.success == true)
                                                this.fireEvent('nodeupdatesuccess', options.editNode, options.editCol, newval, oldval);
                                              else {
                                                options.editNode.cols[options.editColIndex] = oldval;        //for internal use only
                                                options.editNode.attributes[options.editColIndex] = oldval;  //duplicate into array of node attributes
                                                options.editCol.innerHTML = oldval;
                                                this.fireEvent('nodeupdatefailure', options.editNode, options.editCol, newval, oldval);
                                              }
                                              //TODO Remove loader
                                            },
                                  failure : function(response, options) {
                                              options.editNode.cols[options.editColIndex] = oldval;        //for internal use only
                                              options.editNode.attributes[options.editColIndex] = oldval;  //duplicate into array of node attributes
                                              options.editCol.innerHTML = oldval;
                                              this.fireEvent('nodeupdatefailure', options.editNode, options.editCol, newval, oldval);
                                              //TODO Remove loader
                                            },
                                  scope         : this,
                                  editNode      : this.editNode,
                                  editCol       : this.editCol,
                                  editColIndex  : this.editColIndex
                                })
                              );
                              this.editNode.cols[this.editColIndex] = newval;        //for internal use only
                              this.editNode.attributes[this.editColIndex] = newval;  //duplicate into array of node attributes
                              this.editCol.innerHTML = newval;
                              //TODO Add loader
                            }
    });
    Hope it helps...
    It still doesn't resolve the issue with the correct cell being edited WRT the one being double-clicked when two cells have an identical value.
    I'll try to find the solution soon.

    Mehdi
    Last edited by DhakouaniM; 10 Nov 2008 at 10:10 AM. Reason: Corrections...