向jqGrid Treegrid模型添加新行

时间:2011-09-07 16:56:06

标签: javascript jquery jqgrid treegrid

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

2 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分: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()中的一个小错误,它阻止我们使用它向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);

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