Your Privacy Matters: We use our own and third-party cookies to improve your experience on our website. By continuing to use the website we understand that you accept their use. Cookie Policy
395
My partial solution for virtual grid keyboard problems
posted

(If you've solved all the virtual grid issues in the meantime, then please tell me :)

It's been a while, so I thought I would post my actual attempt at this. This is our event for the KeyDownHandler, and it intercepts the cursor up and down keys.

To hook up the event, you would make a call like this:

grid.DisplayLayout.ClientSideEvents.KeyDownHandler = "gridKeyDown";

The first function is just a sub-scroll function to make sure that a particular grid cell is visible. Sometimes, in virtual mode, there can be more rows than are displayable just by having some tall rows. This function makes sure the cell you cursor to is visible:

function scrollElementIntoContainerView(elem, containerElem) {

    var t = elem.offsetTop;
    var h = elem.offsetHeight;
    var ct = containerElem.scrollTop;
    var ch = containerElem.clientHeight;
    if (t < ct)
        containerElem.scrollTop = t;
    if (t + h > ct + ch)
        containerElem.scrollTop = t + h - ch;
}

Another couple of utility functions for the next bit:

function absoluteIndexForCell(cell) {
    return igtbl_parseInt(cell.Row.Node.getAttribute("i"));
}

function absoluteIndexForRow(row) {
    return igtbl_parseInt(row.Node.getAttribute("i"));
}

The next bit is the key handler itself. It's a little bit, so my apologies:

function gridKeyDown(gridName, cellID, key) {
 
    var webGrid = igtbl_getGridById(gridName);
    var cell = webGrid.getActiveCell();
    var nextCell = null;
    var nextRow = null;
    var row;
 
    if (cell)
        row = cell.Row;
    else
        row = webGrid.getActiveRow();
 
    var de;
    var oldTop;
 
    switch (key) {
        case 38: // cursor up
            if (cell && cell.Row.getPrevRow(true, true)) {
                var nr = cell.Row.getPrevRow(true, true);
                while (!nextCell && nr) {
                    nextCell = nr.getCellByColumn(cell.Column);
                    nr = nr.getPrevRow(true, true);
 
                    if (nextCell && nextCell.Element == null) nextCell = null;
                }
            }
            else if (row)
                nextRow = row.getPrevRow(true, true);
 
            var serverScroll = false;
 
            if (nextCell || nextRow) {
 
                de = webGrid.getDivElement();
                oldTop = webGrid._scrElem.scrollTop;
                de.setAttribute("noOnScroll", true);
                try {
                    if (nextCell) {
                       scrollElementIntoContainerView(nextCell.Element, webGrid.DivElement);
                       webGrid.clearSelectionAll();
                        nextCell.activate();
                        nextCell.select(true, true);
                        // Bring up editor if possible
                        if (nextCell.hasButtonEditor(igtbl_cellButtonDisplay.OnMouseEnter))
                           igtbl_showColButton(gridName, nextCell.Element);
                    }
                    else {
                        scrollElementIntoContainerView(nextRow.Element, webGrid.DivElement);
                        nextRow.activate();
                        nextRow.select(true, true);
                    }
                }
                finally {
                    webGrid.cancelNoOnScrollTimeout = window.setTimeout("igtbl_cancelNoOnScroll('" +
                           webGrid.Id + "')", 100);
                }
 
            }
            else {
                if (cell && absoluteIndexForCell(cell) > 0)
                    serverScroll = true;
                else if (row && absoluteIndexForRow(row) > 0)
                    serverScroll = true;
            }
 
            if (serverScroll && cell) {
                YOUR_NAVIGATE_TO_PREVIOUS_RECORDS();
            }
            return true;
            break;
        case 40: // cursor down
            if (cell && cell.Row.getNextRow(true, true)) {
                var nextRow = cell.Row.getNextRow(true, true);
                while (!nextCell && nextRow) {
                    nextCell = nextRow.getCellByColumn(cell.Column);
                    nextRow = nextRow.getNextRow(true, true);
 
                    if (nextCell && nextCell.Element == null) nextCell = null;
                }
            }
            else if (row)
                nextRow = row.getNextRow(true, true);
 
            var serverScroll = false;
 
            if (nextCell || nextRow) {
 
                de = webGrid.getDivElement();
                oldTop = webGrid._scrElem.scrollTop;
                de.setAttribute("noOnScroll", true);
                try {
                    if (nextCell) {
                        scrollElementIntoContainerView(nextCell.Element, webGrid.DivElement);
                        webGrid.clearSelectionAll();
                        nextCell.activate();
                        nextCell.select(true, true);
                        // Bring up editor if possible
                        if (nextCell.hasButtonEditor(igtbl_cellButtonDisplay.OnMouseEnter))
                            igtbl_showColButton(gridName, nextCell.Element);
                    }
                    else {
                        scrollElementIntoContainerView(nextRow.Element, webGrid.DivElement);
                        nextRow.activate();
                        nextRow.select(true, true);
                    }
                }
                finally {
                    webGrid.cancelNoOnScrollTimeout = window.setTimeout("igtbl_cancelNoOnScroll('" +
                           webGrid.Id + "')", 100);
                }
 
            }
            else {
// custom code to prevent over-retrieval
                if (cell && absoluteIndexForCell(cell) < webGrid.RowsServerLength)                     serverScroll = true;                 else if (row && absoluteIndexForRow(row) < webGrid.RowsServerLength)                     serverScroll = true;             }               if (serverScroll) {                 YOUR_NAVIGATE_TO_NEXT_RECORDS();             }               return true;     } }

Essentially, when the serverScroll variable turns to true, it means you have bumped into the returned rows and you have some work to do to retrieve more rows from the grid (in the direction indicated by which cursor key was pressed, of course).

The noOnScroll pieces ensure that the cursoring does not trigger any unnecessary scroll events - they interfere pretty awfully otherwise :) You can't turn it off directly within this event handler, though, so it uses the trick I've seen in the JavaScript a fair bit: throwing the deactivation into a setTimeout.

The webGrid.RowsServerLength is my own addition, and is technically not necessary. We add it in to our web service call response as an indication of how many rows there are on the server. So in this case, if you're on the last virtual row, hitting cursor down will not try to hit the server for more data. It could easily be implemented as some sort of EndOfData boolean property instead.