【问题标题】:Add new rows to jqGrid Treegrid model将新行添加到 jqGrid Treegrid 模型
【发布时间】:2011-09-07 16:56:06
【问题描述】:

我们创建了一个代表文件系统的 jqGrid TreeGrid,其中分支是文件夹,叶子是文件。我们已经在 TreeGrid 中实现了使用 addChildNode 创建新“文件”的功能,这已经足够好了。但是,我们还想添加创建新文件夹的功能。我们的脚本可以创建新文件夹,但它们不会立即显示在 TreeGrid 上,除非它或页面重新加载。但是,重新加载 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"}
]}

【问题讨论】:

  • 添加代码总是很有帮助的,因为它可以获得许多额外的重要信息。您能否描述更多有关您使用的 TreeGrid 的信息。您是使用本地数据还是从服务器加载数据。您是一次加载整个网格还是在扩展其父节点时加载子节点?您拥有哪种网格模型:嵌套集模型或邻接模型。您如何获得有关应添加到树形网格中的新文件夹的信息?会从某些页面输入控件中填充信息还是从服务器加载?
  • 我们使用邻接模型,并随着节点的扩展从 MySQL 数据库中以 JSON 请求的形式获取数据。通过 AJAX 请求在数据库中创建新文件夹记录,以 JSON 请求返回有关新文件夹的信息。添加代码。
  • 对不起,我还是不明白情况。首先,使用来自服务器的数据填充树网格。如果用户单击树节点,则将从服务器加载该节点的子节点。为什么需要再添加一个节点(文件夹)?为什么新文件夹的数据包含父级 ("parent":1)?可能了解您如何填充网格与您的主要问题有关。您写了关于“获取数据”的文章,但来自数据库。我无法想象这样的情况。如果您从数据库中进行 SELECT,您可以将所有结果发送到网格。是这样吗?
  • 我们无法一次获取所有数据,但可能只是没有正确实现。创建新节点的原因是因为每个节点代表一个文件夹,用户可以创建新的文件夹。如果我们创建一个新文件夹,它会在数据库中创建条目,但不会更新网格,因此我们创建一个新节点以显示该文件夹是实际创建的。另一个可接受的解决方案是刷新新创建的文件夹的父节点。
  • 是的,我们最初将网格显示为仅根节点。在扩展节点时,该节点的子节点被检索并发送到网格。我们无法实现一次获取所有数据的网格。

标签: javascript jquery jqgrid treegrid


【解决方案1】:

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

为了表明您应该非常小心新添加行的 id,我在演示中添加了两个按钮:“插入树节点”和“插入具有唯一 rowid 的树节点”。第一个按钮使用您发布的数据中的 id="1113"。一键点击按钮工作正常。第二次单击将插入具有重复 ID 的行,这将是一个错误。您可以在不同的网络浏览器中看到不同的错误。第二个按钮使用$.jgrid.randId() 生成唯一的rowid。在您的场景中它可能不是一个选项,但它在 local 树网格的情况下非常有效(就像在我的演示中一样)。

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

【讨论】:

    【解决方案2】:

    我们通过扩展 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() 中的一个小错误,该错误使我们无法使用它为expandNode() 或我们新创建的reloadNode() 提供record 参数。问题是 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 函数可能对很多人有用。我已经在这里发布了,以防它不被批准。

    【讨论】:

    • 这听起来很有趣,但在你使用upvoting之前,对我的回答写评论是有礼貌的。此外,您在回答中描述了删除节点(delTreeNode),但您的问题是关于节点的添加。可能是您跳过的描述以及您正在解决的关于delTreeNode 的一些问题。一般来说,如果需要添加新节点,删除现有子节点是错误的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多