Search code examples
jqgridfree-jqgrid

free-jqGrid 4.15.6 ExpandNode producing runtime error


I recently upgraded from the original Tony Tomov's jqGrid v4.5.4 to Oleg's free-jqGrid 4.15.6.

When using 4.5.4, the code below worked perfect, but in 4.15.6, it does not. The run-time error is produced by the two calls to expandNode and expandRow located in the forceNodeOpen() function. The error given:

TypeError: rc1 is undefined

The forceNodeOpen() function is used to force all ancestor nodes of the current treegrid node to show as expanded. Much like a table of contents...if we load an initial topic node, we want the whole topic hierarchy to be expanded:

// force a node (if expandable) to stay expanded
function forceNodeOpen(rowid)
{
    var record = $("#tree").jqGrid('getRowData', rowid);
    var div = $('tr#'+rowid).find('div.ui-icon.treeclick');
    div.removeClass('ui-icon-triangle-1-e tree-plus').addClass('ui-icon-triangle-1-s tree-minus');
    **$('#tree').jqGrid('expandNode', record);**    
    **$('#tree').jqGrid('expandRow', record);**

    // get all ancestoral parents and expand them
    // *NOTE*: the getAncestorNodes function of grid was not usable for 
    //         some reason as the same code below just would not work 
    //         with the return array from getAncestorNodes
    var parent = $("#tree").jqGrid('getNodeParent', record);
    while(parent)
    {
        forceNodeOpen(parent['id']);
        parent = $("#tree").jqGrid('getNodeParent', parent);
    }
}

// using topic url, get the tree row id
function getTopicID(topic)
{
    var nodes = $('#tree').jqGrid('getRowData');
    var rowid = 1;
    $.each(nodes, function(e,i)
    {
        var url = $(this).attr('url');
        if(url == topic)
        {
            rowid = $(this).attr('id');
            return false;
        }
    });

    return rowid;
}

// post request to help server via ajax
function loadTopic(topic)
{
    // no need to load again
    if(loadedtopic == topic) { return false; }

    // select the topic node
    var rowid = getTopicID(topic);
    loading = true;
    $('#tree').jqGrid('setSelection', rowid);
    forceNodeOpen(rowid);
    loading = false;

    // wipe content
    $('h1#help_content_topic span:first').html('Loading...');
    $('div#help_content').html('');

    // block UI for ajax posting
    blockInterface();

    // request help content
    $.ajax(
    {
        type: 'POST', 
        url: '/index.php',
        data: { 'isajax': 1, 'topic': topic },
        success: function(data)
        { 
            $.unblockUI();
            $('h1#help_content_topic span:first').html(data['topic']);
            $('div#help_content').html(data['content']);
            return false;
        }
    });

    // save current topic to prevent loading same topic again
    loadedtopic = topic;
}

// table of contents
$('#tree').jqGrid({
    url: "topics.php",
    datatype: "xml",
    autowidth: true,
    caption: "Help Topics",
    colNames: ["id","","url"],
    colModel: [
        {name: "id",width:1,hidden:true, key:true},
        {name: "topic", width:150, resizable: false, sortable:false},
        {name: "url",width:1,hidden:true}
    ],
    ExpandColClick: true,
    ExpandColumn: 'topic',
    gridview: false,
    height: 'auto',
    hidegrid: false,
    pager: false,
    rowNum: 200,
    treeGrid: true,
    treeIcons: {leaf:'ui-icon-document-b'},

    // auto-select topic node
    gridComplete: function()
    {
        // save current topic to prevent loading same topic again
        loadedtopic = '<? echo($topic) ?>';
        var rowid = getTopicID('<? echo($topic) ?>');
        $('#tree').jqGrid('setSelection', rowid);
        forceNodeOpen(rowid);
        $.unblockUI();
    },

    // clear initial loading
    loadComplete: function()
    {
        loading = false;
    },

    onSelectRow: function(rowid)
    {
        // ignore initial page loads
        if(loading) { return false; }

        // load the selected topic
        var topic = $("#tree").jqGrid('getCell',rowid,'url');
        loadTopic(topic);
    }
});

The forceNodeOpen(rowid) is invoked from the loadTopic() function, which is called inside the onSelectRow() event of the treegrid.

Not sure what 4.5.4 did that allowed this code to work but 4.15.6 finds it to be an error. The offending line in 4.15.6.src.js:

expandNode: function (rc) { 
...
if (p.treedatatype !== "local" && !base.isNodeLoaded.call($($t), p.data[p._index[id]]) && !$t.grid.hDiv.loading) {
// set the value which will be used during processing of the server response
// in readInput
p.treeANode = rc1.rowIndex;
p.datatype = p.treedatatype;
...});

I have only included a few lines from the above core function. It's the p.treeANode = rc1.rowIndex that throws the error.

I have to be missing something but do not know what. Hoping somebody can tell me what to do. If I remark out the two expandNode and expandRow treegrid function calls in forceNodeOpen() function, the system does not error out and the desired topic loads. But the hierarchy is not expanded as desired.


START EDIT 1


The server-side code that returns the topic nodes:

echo("<?xml version='1.0' encoding='UTF-8'?>\n");

require('db.php');

echo("<rows>\n");
echo("<page>1</page>\n");
echo("<total>1</total>\n");
echo("<records>1</records>\n");

$sql = "SELECT node.id, node.parentid, node.topic, node.url, node.lft, node.rgt, (COUNT(node.parentid) - 1) AS depth 
            FROM helptopics AS node, helptopics AS parent 
                WHERE node.lft BETWEEN parent.lft AND parent.rgt
                    GROUP BY node.url ORDER BY node.lft";
$stmt = AMDB::selectStatement($sql);
while($data = $stmt->fetch(PDO::FETCH_ASSOC))
{
    $id = $data['id'];
    $pid = $data['parentid'];
    $topic = $data['topic'];
    $url = $data['url'];
    $lft = $data['lft'];
    $rgt = $data['rgt'];
    $leaf = $rgt - $lft == 1 ? 'true' : 'false';
    $exp = 'false';
    $dep = $data['depth'];

    echo("<row><cell>{$id}</cell><cell>{$topic}</cell><cell>{$url}</cell><cell>{$dep}</cell><cell>{$lft}</cell><cell>{$rgt}</cell><cell>{$leaf}</cell><cell>{$exp}</cell></row>\n");
}

echo("</rows>\n");
exit();

END EDIT 1



Solution

  • I see that you use

    var record = $("#tree").jqGrid('getRowData', rowid);
    

    to get node data of TreeGrid. It wasn't good, but it worked in old jqGrid because it saved internal jqGrid data twice: once as local data and once more time in hidden cells of the grid.

    You should use getLocalRow instead of getRowData:

    var record = $("#tree").jqGrid('getLocalRow', rowid);
    

    The code will work on both old jqGrid and free jqGrid. Additionally, getLocalRow has always better performance comparing with getRowData even in jqGrid 4.5.4.