1

我们创建了一个代表文件系统的 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"}
]}
4

2 回答 2

2

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

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

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

于 2011-09-12T12:43:40.017 回答
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:''}});
            }
        });
    },

这与 save 相同,expandNode()因为它不检查节点是否开始扩展,并强制它为该节点的子元素发送 AJAX 请求。这样,我们总是有最新的孩子。

最后,我们修复了 中的一个小错误getRowData(),该错误使我们无法使用它向record其中一个expandNode()或我们新创建的reloadNode(). 问题是_id_JSON 返回中的字段从未创建或填充。将其添加到固定两者中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函数可能对很多人有用。我已经在这里发布它以防它不被批准。

于 2011-09-14T15:50:41.923 回答