Как перехватить событие ng-keypress / $ при нажатии за пределами div? - PullRequest
0 голосов
/ 14 апреля 2020

Я строю игру судоку в AngularJS. Чего я хочу добиться, так это перехватить нажатие клавиши ng, даже если я нажму за пределами div на странице. Посмотрите, например, http://sudoku.com/, если вы выберете ячейку, а затем щелкните мышью в любом месте на странице и после этого, если вы нажмете на какое-либо число, оно изменит это число в ячейке. , Как мне этого добиться?

Пожалуйста, посмотрите на код HTML ниже:

<table class="sudoku-board" ng-init="getSudoku()" id="sudoku"
                                   ng-class="{'paused': visible}">
                                <tbody>
                                    <tr class="sudoku-row" ng-repeat="sudoku in sudokuGrid track by $index"
                                        ng-init="row = $index">
                                        <td class="sudoku-col sudoku-cell" ng-repeat="number in sudoku track by $index"
                                            ng-init="col = $index" ng-class="{'highlight': colSelected === col || isHighlight(row, col) || rowSelected === row,
                                            'highlight-number':getValue === number.substring(0, 1), 'selected':isSelected === ((row*10) + col), 'paused': visible}"
                                            ng-click="selectedCell(row, col)"
                                            ng-keydown="insertNum($event, row, col);" tabindex="1">
                                            <span class="cell-value"
                                                  ng-class="{'empty': number === null || number.charAt(number.length-1) === '!', 'default': number !== null, 'paused': visible}"
                                                  ng-bind="number.substring(0, 1)"></span>
                                        </td>
                                    </tr>
                                </tbody>
                            </table>

При ng-keydown я запускаю эту функцию:

// handle inserted value
$scope.insertNum = function (e, row, col, number) {
    console.log("Number: " + number);
    $scope.selectedCol = col; // get selected column
    $scope.selectedRow = row; // get selected row
    console.log(e);
    if (e !== undefined) {
        var keyCode = e.keyCode || e.charCode; // assign key & char code
        if ((keyCode < 49 || ((keyCode > 57 && keyCode < 97) || keyCode > 105)) && (keyCode !== 8 && keyCode !== 46))
            return false; // if clicked button/ event is not a number or delete/ backspace button -> return false

        if (e.currentTarget.children[0].classList[2] === 'empty') // check if clicked cell is empty
            if (keyCode === 8 || keyCode === 46) { // if clicked delete/ backspace remove the current value
                e.currentTarget.children[0].innerHTML = null;
                $scope.sudokuGrid[row][col] = null;
                $(e.target).removeClass("incorrect");
                $(e.target).removeClass("correct");
                $scope.handleErrorClass();
                $scope.getValue = false;
            }
            else { // when number is clicked
                e.currentTarget.children[0].innerHTML = e.key; //  insert that number in the cell
                $scope.sudokuGrid[row][col] = e.key + "!";
                $scope.checkCurrentNumber(row, col);
                $scope.getCurrentNumber(row, col);

                // if inserted number is correct add class
                if (e.key === $scope.sudokuGridSolved[row][col]) {
                    console.log("Correct");
                    $(e.target).removeClass("incorrect");
                    $(e.target).addClass("correct");
                }
                // add incorrect class if inserted number is not correct
                else {
                    console.log("Incorrect");
                    $(e.target).removeClass("correct");
                    $(e.target).addClass("incorrect");
                }
                //$scope.sudokuGrid[row][col] = e.key;
            }
    }
    else {
        if (number !== null && $("tr:eq(" + $scope.selectedRow + ") td:eq(" + $scope.selectedCol + ") span").hasClass("empty")) {
            $("tr:eq(" + $scope.selectedRow + ") td:eq(" + $scope.selectedCol + ") span").html(number);
            $scope.sudokuGrid[row][col] = number + "!";
            $scope.checkCurrentNumber(row, col);
            $scope.getCurrentNumber(row, col);

            // if inserted number is correct add class
            if ($scope.getValue === $scope.sudokuGridSolved[row][col]) {
                console.log("Correct");
                $("tr:eq(" + $scope.selectedRow + ") td:eq(" + $scope.selectedCol + ")").removeClass("incorrect");
                $("tr:eq(" + $scope.selectedRow + ") td:eq(" + $scope.selectedCol + ")").addClass("correct");
            }
            // add incorrect class if inserted number is not correct
            else {
                console.log("Incorrect!");
                $("tr:eq(" + $scope.selectedRow + ") td:eq(" + $scope.selectedCol + ")").removeClass("correct");
                $("tr:eq(" + $scope.selectedRow + ") td:eq(" + $scope.selectedCol + ")").addClass("incorrect");
            }
        }
    }
    $scope.checkForIdenticalValues();
}

1 Ответ

0 голосов
/ 14 апреля 2020

Таким образом, проблема в том, что ng-keydown находится на теге <td>, поэтому функция будет вызываться только тогда, когда она находится в фокусе на текущем элементе, но звучит так, будто вы хотите ответить на событие нажатия клавиши в любом месте на странице. .

Вы можете сделать это, используя ng-keydown в теге body вместо <td>, а затем заставить функцию транслировать событие, которое можно прослушивать из компонента sudoku для запуска insertNum logi * 1024. *. Вот так:

<body ng-keydown="onMyKeydownEvent($event)"> 

Затем вы связали функцию на $rootScope в run() для трансляции события.

app.run(function($rootScope) {
  $rootScope.onMyKeydownEvent = function(e) {
    $rootScope.$broadcast("MyKeydownEvent", e);
  };
});

После этого добавьте слушатель к вашему компоненту.

$scope.$on("MyKeydownEvent", function(e) {
  // insertNum logic goes here.
});

Вам также нужно будет внести некоторые изменения в логи c, поскольку такие вещи, как e.currentTarget и $scope.selectedCol = col; $scope.selectedRow = row; больше не будут работать должным образом. Вместо этого ng-click="selectedCell(row, col)" на теге <td> должен отвечать за установку необходимых данных ячейки в область видимости, чтобы их можно было использовать в событии.

...