Javascript 将新行添加到jqGrid Treegrid模型
我们创建了一个jqGrid TreeGrid,它表示一个文件系统,其中分支是文件夹,叶是文件。我们已经在TreeGrid中实现了通过使用Javascript 将新行添加到jqGrid Treegrid模型,javascript,jquery,jqgrid,treegrid,Javascript,Jquery,Jqgrid,Treegrid,我们创建了一个jqGrid TreeGrid,它表示一个文件系统,其中分支是文件夹,叶是文件。我们已经在TreeGrid中实现了通过使用addChildNode创建新“文件”的功能,该功能运行得很好。但是,我们还希望添加创建新文件夹的功能。我们的脚本可以创建新文件夹,但除非重新加载它或页面,否则它们不会立即显示在TreeGrid上。但是,重新加载TreeGrid将折叠所有文件夹,这尤其令人讨厌 有没有一种方法可以有选择地刷新TreeGrid的节点,或者在其中添加一个新的分支以实现功能?我已经看到
addChildNode
创建新“文件”的功能,该功能运行得很好。但是,我们还希望添加创建新文件夹的功能。我们的脚本可以创建新文件夹,但除非重新加载它或页面,否则它们不会立即显示在TreeGrid上。但是,重新加载TreeGrid将折叠所有文件夹,这尤其令人讨厌
有没有一种方法可以有选择地刷新TreeGrid的节点,或者在其中添加一个新的分支以实现功能?我已经看到了一些关于addJSONData
的部分文档,但是使用此函数会完全清除TreeGrid,直到刷新为止。我还尝试使用addChildNode
和更改某些属性,并尝试使用DOM操作手动添加行中的内容;但是,这两种方法都会打断插入的节点
编辑:
为新文件夹返回的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"}
]}
演示如何使用方法添加树节点。我添加了JSON数据,您发布了“loaded”:true部分,因为我在测试中没有使用服务器组件,我想立即加载treegrid
为了表明您应该非常小心地使用新添加行的ID,我在演示中添加了两个按钮:“插入树节点”和“插入具有唯一rowid的树节点”。第一个按钮使用您发布的数据中的id=“1113”。只需点击按钮即可正确工作。第二次单击将插入id重复的行,这将是一个错误。在不同的web浏览器中可以看到不同的错误。第二个按钮使用$.jgrid.randId()
生成唯一的rowid。在您的场景中,这可能不是一个选项,但在本地树网格的情况下,它工作得非常完美(就像在我的演示中一样)
另一个问题是,您在演示中对根元素使用了“parent”:“0”。正确的将是“父项”:null
或“父项”:“null”
(请参阅)。此外,名为“parent\u id”
的属性将被忽略。我从演示中删除了一些设置,以便可以在treegrid中使用本地排序。我们通过扩展jqGrid源的功能解决了这个问题。首先,我们创建了一个函数,可以删除特定文件夹的所有子节点(包括文件夹/分支和文件/叶子),以便重新加载它们,从而获得最新的子节点集。此函数采用整数rowid
,就像delTreeNode()
一样
这与expandNode()
save相同,因为它不会检查节点是否已开始展开,并强制它为该节点的子元素发送AJAX请求。这样,我们总是有最新的孩子
最后,我们修复了getRowData()
中的一个小错误,它阻止我们使用它向expandNode()
或新创建的reloadNode()
提供record
参数。问题是JSON返回中的\u id\u
字段从未创建或填充。在固定的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;
},
我们称这个函数为
var parentid = ret.rows[0].parent;
var parent = grid.jqGrid('getRowData', parentid);
grid.jqGrid('reloadNode', parent);
这些函数将删除父节点的所有子节点,然后从数据库发送一个新的、更新的列表的AJAX请求。如果可能的话,我将把它推到jqGrid Github上,因为重载
函数可能对很多人有用。我在这里发布了它,以防它未被批准。添加代码总是非常有用的,因为它可以获得许多其他重要信息。你能详细描述一下你使用的树丛吗。您是使用本地数据还是从服务器加载数据。是一次加载整个网格,还是在展开其父节点时加载子节点?您有哪种网格模型:嵌套集模型或邻接模型。如何获取应添加到treegrid中的新文件夹的信息?将填充来自某些页面输入控件的信息,或者是否将从服务器加载?我们使用邻接模型,并在扩展节点时从MySQL数据库中以JSON请求的形式获取数据。通过AJAX请求在数据库中创建新文件夹记录,在JSON请求中返回有关新文件夹的信息。添加了代码。抱歉,但我仍然不了解情况。首先,用来自服务器的数据填充树网格。如果用户单击树节点,则将从服务器加载节点的子节点。为什么需要再添加一个节点(文件夹)?为什么新文件夹的数据包含父项(“parent”:1
)?也许你对如何填充网格的理解与你的主要问题有关。你曾写过关于获取“零碎的数据”,但是是从数据库中获取的。我无法想象这种情况。如果从数据库中选择,则可以将所有结果发送到网格。是吗?我们无法一次获取所有数据,但可能只是没有正确地实现。创建新节点的原因是,每个节点代表一个文件夹,用户可以为其创建新的文件夹。如果我们创建一个新文件夹,它会在数据库中创建条目,但不会更新网格,因此我们会创建一个新节点来显示文件夹是实际创建的。另一个可接受的解决方案是刷新新创建的文件夹的父节点。是的,我们最初只将网格显示为根节点。展开节点时,将检索该节点的子节点并将其发送到网格。我们无法实现一个一次获取所有数据的网格。这听起来很有趣,但在使用upvoting之前,最好写
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:''}});
}
});
},
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;
},
{{"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);