Navigate the UI using only keyboard

后端 未结 5 1621
故里飘歌
故里飘歌 2020-12-31 15:21

I\'m trying to navigate thru a list of records using only keyboard. When the page loads, the default \"focus\" should be on the first record, when the user clicks the down a

5条回答
  •  甜味超标
    2020-12-31 15:43

    You could create a table navigation service which tracks the current row and exposes navigation methods to modify the current row's value and sets focus to the row.

    Then all you would need to do is create a key binding directive where you could track key down events and fire the exposed methods from the table navigation service, on key up or key down.

    I have used a controller to link the service methods to the key binding directive via a configuration object called 'keyDefinitions'.

    You can extend the keyDefinitions to include the Enter key (Code: 13) and hook on to the selected $index value via the service property 'tableNavigationService.currentRow' or '$scope.data', then pass it as a parameter to your own custom submit() function.

    I hope that this is helpful to somebody.

    I have posted my solution to this issue at the following plunker location:

    Keyboard Navigation Service Demo

    HTML:

    first name last name birth date balance email
    {{row.firstName | uppercase}} {{row.lastName}} {{row.birthDate | date}} {{row.balance | currency}} email

    CONTROLLER:

      app.controller('navigationDemoController', [
        '$scope',
        'tableNavigationService',
        navigationDemoController
      ]);
    
      function navigationDemoController($scope, tableNavigationService) {
        $scope.data = tableNavigationService.currentRow;
    
        $scope.keyDefinitions = {
          'UP': navigateUp,
          'DOWN': navigateDown
        }
    
        $scope.rowCollection = [
          {
            firstName: 'Chris',
            lastName: 'Oliver',
            birthDate: '1980-01-01',
            balance: 100,
            email: 'chris@email.com'
          },
          {
            firstName: 'John',
            lastName: 'Smith',
            birthDate: '1976-05-25',
            balance: 100,
            email: 'chris@email.com'
          },
          {
            firstName: 'Eric',
            lastName: 'Beatson',
            birthDate: '1990-06-11',
            balance: 100,
            email: 'chris@email.com'
          },
          {
            firstName: 'Mike',
            lastName: 'Davids',
            birthDate: '1968-12-14',
            balance: 100,
            email: 'chris@email.com'
          }
        ];
    
        $scope.activeRowIn = function(index) {
          return index === tableNavigationService.currentRow;
        };
    
        function navigateUp() {
          tableNavigationService.navigateUp();
        };
    
        function navigateDown() {
          tableNavigationService.navigateDown();
        };
    
        function init() {
          tableNavigationService.setRow(0);
        };
    
        init();
      };
    })();
    

    SERVICE AND DIRECTIVE:

    (function () {
      'use strict';
    
      var app = angular.module('tableNavigation', []);
    
      app.service('tableNavigationService', [
        '$document',
        tableNavigationService
      ]);
      app.directive('keyWatch', [
        '$document',
        keyWatch
      ]);
    
      // TABLE NAVIGATION SERVICE FOR NAVIGATING UP AND DOWN THE TABLE
      function tableNavigationService($document) {
        var service = {};
    
        // Your current selected row
        service.currentRow = 0;
        service.table = 'tableId';
        service.tableRows = $document[0].getElementById(service.table).getElementsByTagName('tbody')[0].getElementsByTagName('tr');
    
        // Exposed method for navigating up
        service.navigateUp = function () {
            if (service.currentRow) {
                var index = service.currentRow - 1;
    
                service.setRow(index);
            }
        };
    
        // Exposed method for navigating down
        service.navigateDown = function () {
            var index = service.currentRow + 1;
    
            if (index === service.tableRows.length) return;
    
            service.setRow(index);
        };
    
        // Expose a method for altering the current row and focus on demand
        service.setRow = function (i) {
            service.currentRow = i;
            scrollRow(i);
        }
    
        // Set focus to the active table row if it exists
        function scrollRow(index) {
            if (service.tableRows[index]) {
                service.tableRows[index].focus();
            }
        };
    
        return service;
      };
    
      // KEY WATCH DIRECTIVE TO MONITOR KEY DOWN EVENTS
      function keyWatch($document) {
        return {
          restrict: 'A',
          link: function(scope) {
            $document.unbind('keydown').bind('keydown', function(event) {
              var keyDefinitions = scope.keyDefinitions;
              var key = '';
    
              var keys = {
                  UP: 38,
                  DOWN: 40,
              };
    
              if (event && keyDefinitions) {
    
                for (var k in keys) {
                  if (keys.hasOwnProperty(k) && keys[k] === event.keyCode) {
                      key = k;
                  }
                }
    
                if (!key) return;
    
                var navigationFunction = keyDefinitions[key];
    
                if (!navigationFunction) {
                  console.log('Undefined key: ' + key);
                  return;
                }
    
                  event.preventDefault();
                    scope.$apply(navigationFunction());
                    return;
              }
              return;
            });
          }
        }
      }
    })();
    

提交回复
热议问题