0

I'm working on adding some keyboard navigation support for a grid implementation called trNgGrid. I have some of the code working, however I believe a scoping problem is what lies between victory and defeat.

What I'm trying to achieve:

  1. On mouseover, mark grid item as "activated" and add "active" class
  2. on up/down/left/right arrow keys select the next grid row - applying the "activated" status and active class to it.

I have the mousedown functionality implemented and it is working perfectly. On initialization I have an option called gridOptions.selectedIndex that defaults to 0. This option is defined in the main parent directive - see plnkr trNgGrid.js line 945

selectedIndex: '=?' //not sure why the ? really - just mimicking others in this grid directive

On mouseover, a function is called that sets the gridOptions.selectedIndex to the index of the row being moused-over. Each row has an ng-class applied that sets the active class if the $index==gridOptions.selectedIndex.

Code to show how table rows are output using ng-repeat & my ng-class setup - see plnkr trNgGrid.js line 710-714

templatedBodyRowElement.attr("ng-repeat", "gridDisplayItem in filteredItems");
templatedBodyRowElement.attr("ng-init", "gridItem=gridDisplayItem.$$_gridItem");
templatedBodyRowElement.attr("ng-class", "{'" + TrNgGrid.rowSelectedCssClass + "':$index==gridOptions.selectedIndex}");
templatedBodyRowElement.attr("ng-mouseover", "handleMouseOver($index, $event)");

bodyDirective (mouse handling logic) - see plnkr trNgGrid.js line 1086

scope.handleMouseOver = function(index, $event) {
  controller.handleMouseOver(index, $event);
}

Controller function for handlMouseOver() - see plnkr trNgGrid.js line 461

GridController.prototype.handleMouseOver = function (index, $event) {
  this.gridOptions.selectedIndex = index;
}

Now, for keydown... Inside one of the several directives that make up trNgGrid, I am injecting the $document, and adding a $document listener (I need to listen for the arrow keys any time a grid is available on the page - there will never be more than one grid on a page at once). For each keydown that matches the right key codes I call a function that updates the gridOptions.selectedIndex appropriately. Based on the ng-class attribute (active: $index==gridOptions.selectedIndex) this should theoretically apply the "active" class and css styles to the row. However, this is not happening. I am attempting to reference the gridOptions identically to how the mouseover function does, but I'm wondering if the ng-repeat and its scope behavior may be interfering somehow?

Directive that contains the $document listener - see plnkr trNgGrid line 1071

.directive(bodyDirective, [ "$document",
    function ($document) {
        return {
            restrict: 'A',
            require: '^' + tableDirective,
            scope: true,
            compile: function (templateElement, tAttrs) {
                return {
                    pre: function (scope, compiledInstanceElement, tAttrs, controller) {
                        scope.toggleItemSelection = function (item, $event) {
                            controller.toggleItemSelection(scope.filteredItems, item, $event);
                        };
                        scope.doRowClickAction = function (item, $event) {
                            controller.doRowClickAction(scope.filteredItems, item, $event);
                        };
                        scope.handleMouseOver = function(index, $event) {
                            controller.handleMouseOver(index, $event);
                        }
                        scope.navigateRows = function(dir, $event) {
                            controller.navigateRows(dir);
                        }
                        scope.selectRow = function($event) {
                            controller.selectRow();
                        }
                        scope.navigatePage = function(dir, $event) {
                            controller.navigatePage(dir);
                        }
                    },
                    post: function(scope, iElem, tAttrs, controller){
                        // Keyboard Navigation of table
                        $document.on("keydown", function(event) {
                            var keyCode = event.which;
                            switch (keyCode) {
                                case 38: //up arrow 
                                case 37: //left arrow 
                                    scope.navigateRows("up");
                                    break;
                                case 40: //down arrow 
                                case 39: //right arrow 
                                    scope.navigateRows("down");
                                    break;
                                case 13: //enter
                                    scope.selectRow();
                                    break;
                                case 33: //page up 
                                    scope.navigatePage("up");
                                    break;
                                case 34: //page down
                                    scope.navigatePage("down");
                                    break;
                            }                                    
                        });
                    }
                };
            }
        };
    }
])

Controller function that has logic for up/down/left/right/arrow - see plnkr trNgGrid line 468

GridController.prototype.navigateRows = function (dir){
    var count = this.gridOptions.items.length;
    if (count > 1) {
        if (dir === "up") {
            if (this.gridOptions.selectedIndex > 0) {
                this.gridOptions.selectedIndex -= 1;            
            }
        } else {
            if (this.gridOptions.selectedIndex < count-1) {
                this.gridOptions.selectedIndex += 1;
            }
        }
        console.log(this.gridOptions.selectedIndex);
    }
}

I may be asking too much to have someone look at so much code due to how much there is, but I have created a plunk to show what I've done.

http://plnkr.co/edit/y8lXuDa7zodzW4iWG2UV?p=preview

1 Answer 1

1

Solved it. This question clued me into my problem and what had to be done:

How do I update an angularjs page after a scope update?

scope.$apply() was needed. I went ahead and wrapped it around each of the function calls that ended up modifying the scope.

scope.$apply(function(){
  scope.navigateRows("up");
});
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.