2011-09-07 137 views
1

我们创建了一个表示文件系统的jqGrid TreeGrid,其中分支是文件夹,叶子是文件。我们已经在TreeGrid中实现了功能,通过使用addChildNode来创建新的“文件”,这很好地工作。但是,我们还希望添加功能来创建新文件夹。我们的脚本可以创建新的文件夹,但它们不会立即显示在TreeGrid上,除非它或页面被重新加载。但是,重新加载TreeGrid会折叠所有文件夹,这特别烦人。向jqGrid Treegrid模型添加新行

有没有办法选择性地刷新TreeGrid的节点,或者添加一个新的分支,这是功能?我在addJSONData上看到了部分文档,但是使用这个函数完全清除了TreeGrid,直到刷新。我也尝试使用addChildNode并更改某些属性,并试图使用DOM操作手动添加行;但是,这两种方法都会破坏插入的节点。

编辑:

var grid = $("#grid"); 
grid.jqGrid({ 
    treeGrid: true, 
    treeGridModel: "adjacency", 
    ExpandColumn: 'name', 
    ExpandColClick: true, 
    url:"", 
    datatype:"json", 
    colNames:['id','Name','Authorization','Views','Uri'], 
    colModel:[ {name:'id', index:'id', hidden:true, key:true}, 
       {name:'name', index:'name', sorttype:"text", width:3, sortable:false}, 
       {name:'auth',index:'auth', sorttype:"text", sortable:false, hidden:true}, 
       {name:'views',index:'views', sorttype:"integer", width:1, sortable:false, align:"center"}, 
       {name:'uri',index:'uri',sorttype:'text',sortable:false,hidden:true}], 
    jsonReader:{ root:"rows" 
       ,page:"page" 
       ,total:"total" 
       ,records:"records" 
       ,repeatitems:false 
       ,cell:"" 
       ,id:"0" 
       ,userdata:"" 
       }, 
    multiselect:false, 
    autowidth:true, 
    height:"auto", 
    sortable:false, 
    toppager:true, 
    hidegrid: false, 
    loadui: 'block', 
    pager:"#grid_pager", 
    caption: "Files", 
}); 

返回的JSON请求新文件夹看起来是这样的:

ret = {"error":"","total":1,"page":1,"records":1,"rows":[{"id":"1113","name":"test","uri":"accounting\/test\/","parent":1,"isLeaf":false,"expanded":true,"loaded":true}]} 

对此我尝试使用添加:

grid[0].addJSONData(ret); 

初始加载的数据以JSON形式发送:

{"rows":[ 
    {"id":"1","uri":"afolder\/","parent_id":"0","name":"afolder","level":0,"parent":"0","isLeaf":"false"}, 
    {"id":"4","uri":"bfolder\/","parent_id":"0","name":"bfolder","level":0,"parent":"0","isLeaf":"false"}, 
    {"id":"7","uri":"cfolder\/","parent_id":"0","name":"cfolder","level":0,"parent":"0","isLeaf":"false"}, 
    {"id":"20","uri":"dfolder\/","parent_id":"0","name":"dfolder","level":0,"parent":"0","isLeaf":"false"}, 
    {"id":"48","uri":"efolder\/","parent_id":"0","name":"efolder","level":0,"parent":"0","isLeaf":"false"}, 
    {"id":"179","uri":"ffolder\/","parent_id":"0","name":"ffolder","level":0,"parent":"0","isLeaf":"false"}, 
    {"id":"182","uri":"gfolder\/","parent_id":"0","name":"gfolder","level":0,"parent":"0","isLeaf":"false"}, 
    {"id":"186","uri":"hfolder\/","parent_id":"0","name":"hfolder","level":0,"parent":"0","isLeaf":"false"}, 
    {"id":"201","uri":"ifolder\/","parent_id":"0","name":"ifolder","level":0,"parent":"0","isLeaf":"false"}, 
    {"id":"239","uri":"jfolder\/","parent_id":"0","name":"jfolder","level":0,"parent":"0","isLeaf":"false"}, 
    {"id":"253","uri":"kfolder\/","parent_id":"0","name":"kfolder","level":0,"parent":"0","isLeaf":"false"}, 
    {"id":"262","uri":"lfolder\/","parent_id":"0","name":"lfolder","level":0,"parent":"0","isLeaf":"false"}, 
    {"id":"274","uri":"mfolder\/","parent_id":"0","name":"mfolder","level":0,"parent":"0","isLeaf":"false"} 
]} 
+0

添加代码总是非常有帮助,因为它可以获得许多额外的重要信息。你能否介绍一下你使用的TreeGrid?你使用本地数据还是从服务器加载数据?您是否一次加载整个网格,或者在展开其父节点时加载子节点?您拥有哪种网格模型:嵌套集模型或邻接模型。如何获取有关应添加到treegrid中的新文件夹的信息?将填充来自某些页面输入控件的信息,还是将从服务器加载? – Oleg

+0

我们使用邻接模型,并在扩展节点时将数据作为JSON请求从MySQL数据库中获取。有关新文件夹的信息将通过AJAX请求在数据库中创建新文件夹记录的JSON请求中返回。增加了代码。 – shmeeps

+0

对不起,但我还是不了解情况。首先用服务器的数据填充树网格。如果用户点击树节点,节点的子节点将从服务器加载。它是如何来增加一个节点(文件夹)?为什么新文件夹的数据包含父项('“parent”:1')?理解你如何填补网格与你的主要问题有关。你写过关于“获取数据的部分”,但是来自数据库。我无法想象这种情况。如果您从数据库中进行SELECT操作,则可以将所有结果发送到网格。是这样吗? – Oleg

回答

1

我们通过扩展jqGrid源代码的功能解决了这个问题。首先,我们创建了一个函数,可以删除特定文件夹(文件夹/分支和文件/叶子)的所有子节点,以便我们可以重新加载它们,从而得到最新的一组子文件。此功能需要一个整数rowid,就像delTreeNode()一样。

delChildren : function (rowid) { 
    return this.each(function() { 
     var $t = this, rid = $t.p.localReader.id, 
     left = $t.p.treeReader.left_field, 
     right = $t.p.treeReader.right_field, myright, width, res, key; 
     if(!$t.grid || !$t.p.treeGrid) {return;} 
     var rc = $t.p._index[rowid]; 
     if (rc !== undefined) { 
      // nested 
      myright = parseInt($t.p.data[rc][right],10); 
      width = myright - parseInt($t.p.data[rc][left],10) + 1; 
      var dr = $($t).jqGrid("getFullTreeNode",$t.p.data[rc]); 
      if(dr.length>0){ 
       for (var i=0;i<dr.length;i++){ 
        if(dr[i][rid] != rowid) 
         $($t).jqGrid("delRowData",dr[i][rid]); 
       } 
      } 
      if($t.p.treeGridModel === "nested") { 
       // ToDo - update grid data 
       res = $.jgrid.from($t.p.data) 
        .greater(left,myright,{stype:'integer'}) 
        .select(); 
       if(res.length) { 
        for(key in res) { 
         res[key][left] = parseInt(res[key][left],10) - width ; 
     } 
       } 
       res = $.jgrid.from($t.p.data) 
        .greater(right,myright,{stype:'integer'}) 
        .select(); 
       if(res.length) { 
        for(key in res) { 
         res[key][right] = parseInt(res[key][right],10) - width ; 
        } 
       } 
      } 
     } 
    }); 
}, 

然后,我们创建了一个强制重载某个节点(文件夹)的函数。

reloadNode: function(rc) { 
     return this.each(function(){ 
      if(!this.grid || !this.p.treeGrid) {return;} 

      var rid = this.p.localReader.id; 

      $(this).jqGrid("delChildren", rc[rid]); 

      var expanded = this.p.treeReader.expanded_field, 
      parent = this.p.treeReader.parent_id_field, 
      loaded = this.p.treeReader.loaded, 
      level = this.p.treeReader.level_field, 
      lft = this.p.treeReader.left_field, 
      rgt = this.p.treeReader.right_field; 

      var id = $.jgrid.getAccessor(rc,this.p.localReader.id); 
      var rc1 = $("#"+id,this.grid.bDiv)[0]; 

      rc[expanded] = true; 
      $("div.treeclick",rc1).removeClass(this.p.treeIcons.plus+" tree-plus").addClass(this.p.treeIcons.minus+" tree-minus"); 
      this.p.treeANode = rc1.rowIndex; 
      this.p.datatype = this.p.treedatatype; 
      if(this.p.treeGridModel == 'nested') { 
       $(this).jqGrid("setGridParam",{postData:{nodeid:id,n_left:rc[lft],n_right:rc[rgt],n_level:rc[level]}}); 
      } else { 
       $(this).jqGrid("setGridParam",{postData:{nodeid:id,parentid:rc[parent],n_level:rc[level]}}); 
      } 
      $(this).trigger("reloadGrid"); 
      rc[loaded] = true; 
      if(this.p.treeGridModel == 'nested') { 
       $(this).jqGrid("setGridParam",{postData:{nodeid:'',n_left:'',n_right:'',n_level:''}}); 
      } else { 
       $(this).jqGrid("setGridParam",{postData:{nodeid:'',parentid:'',n_level:''}}); 
      } 
     }); 
    }, 

这是一样的expandNode()节省,它不检查节点扩展到开始,并强制发送该节点的子元素的AJAX请求。这样,我们总是有最新的孩子。

最后,我们在getRowData()固定一个小bug,这使我们无法使用它的record论点提供要么expandNode()或新创建的reloadNode()。问题是从未创建或填充JSON返回中的_id_字段。添加固定的expandNode()reloadNode()以下是已更改的来源。不理想,但它的工作原理。

getRowData : function(rowid) { 
    var res = {}, resall, getall=false, len, j=0; 
    this.each(function(){ 
     var $t = this,nm,ind; 
     if(typeof(rowid) == 'undefined') { 
      getall = true; 
      resall = []; 
      len = $t.rows.length; 
     } else { 
      ind = $t.rows.namedItem(rowid); 
      if(!ind) { return res; } 
      len = 2; 
     } 
     while(j<len){ 
      if(getall) { ind = $t.rows[j]; } 
      if($(ind).hasClass('jqgrow')) { 
       $('td',ind).each(function(i) { 
        nm = $t.p.colModel[i].name; 
        if (nm !== 'cb' && nm !== 'subgrid' && nm !== 'rn') { 
         if($t.p.treeGrid===true && nm == $t.p.ExpandColumn) { 
          res[nm] = $.jgrid.htmlDecode($("span:first",this).html()); 
         } else { 
          if($t.p.colModel[i].key != undefined && $t.p.colModel[i].key == true) 
          { 
           try { 
            res["_" + nm + "_"] = $.unformat(this,{rowId:ind.id, colModel:$t.p.colModel[i]},i); 
           } catch (e){ 
            res["_" + nm + "_"] = $.jgrid.htmlDecode($(this).html()); 
           } 
          } 
          try { 
           res[nm] = $.unformat(this,{rowId:ind.id, colModel:$t.p.colModel[i]},i); 
          } catch (e){ 
           res[nm] = $.jgrid.htmlDecode($(this).html()); 
          } 
         } 
        } 
       }); 
       if(getall) { resall.push(res); res={}; } 
      } 
      j++; 
     } 
    }); 
    return resall ? resall: res; 
}, 

最后,我们拉这一切都在一起如下,以JSON返回对象从创建一个文件夹,例如

{{"id":"1267", "name":"test15", "uri":"sample1\/test15\/", "parent_id":1, "parent":1, "isLeaf":false} 

我们称喜欢

var parentid = ret.rows[0].parent; 

var parent = grid.jqGrid('getRowData', parentid); 

grid.jqGrid('reloadNode', parent); 

功能的功能删除父节点的所有子节点,然后从数据库发送一个AJAX请求给新的更新列表。如果可能的话,我将把它推到jqGrid Github上,因为reload函数可能对许多人有用。如果未获批准,我已将其张贴在此处。

+0

这听起来很有趣,但在使用upvoting之前,对我的答案写评论会很有礼貌。此外,你在你的回答中描述了*删除节点('delTreeNode'),但你的问题是关于*添加节点。可能这是一个问题,你跳过的描述和你正在解决的关于'delTreeNode'的问题。一般来说,如果需要*添加新节点*删除现有的子节点是错误的。 – Oleg

2

The demo显示如何使用addChildNode方法添加树节点。我在JSON数据中添加了你发布的"loaded":true部分,因为我在测试中使用了没有服务器组件,我想一次加载treegrid。

为了表明您应该非常小心添加的新行的ID,我在演示中添加了两个按钮:“插入树节点”和“插入具有唯一rowid的树节点”。第一个按钮使用您发布的数据中的id =“1113”。点击按钮工作正确。第二次点击将插入具有id重复的行,这将是一个错误。您可以在不同的网页浏览器中看到不同的错误。第二个按钮使用$.jgrid.randId()来生成唯一的rowid。这可能不是您的方案中的一个选项,但它适用于本地树形网格(如我的演示中所示)。

另一个问题是您在演示中使用“parent”:“0”作为根元素。正确的将是"parent":null"parent":"null"(请参阅the answer)。此外,名称为"parent_id"的房产将被忽略。我从演示中删除了一些设置,以便可以在treegrid中使用本地排序。