Javascript 将新行添加到jqGrid Treegrid模型

Javascript 将新行添加到jqGrid Treegrid模型,javascript,jquery,jqgrid,treegrid,Javascript,Jquery,Jqgrid,Treegrid,我们创建了一个jqGrid TreeGrid,它表示一个文件系统,其中分支是文件夹,叶是文件。我们已经在TreeGrid中实现了通过使用addChildNode创建新“文件”的功能,该功能运行得很好。但是,我们还希望添加创建新文件夹的功能。我们的脚本可以创建新文件夹,但除非重新加载它或页面,否则它们不会立即显示在TreeGrid上。但是,重新加载TreeGrid将折叠所有文件夹,这尤其令人讨厌 有没有一种方法可以有选择地刷新TreeGrid的节点,或者在其中添加一个新的分支以实现功能?我已经看到

我们创建了一个jqGrid 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);