¿Cómo usar un evento de pulsación de tecla en AngularJS?

410

Quiero ver el evento de presionar la tecla enter en el cuadro de texto a continuación. Para que quede más claro, estoy usando a ng-repeatpara poblar el cuerpo. Aquí está el HTML:

<td><input type="number" id="closeqty{{$index}}" class="pagination-right closefield" 
    data-ng-model="closeqtymodel" data-ng-change="change($index)" required placeholder="{{item.closeMeasure}}" /></td>

Este es mi módulo:

angular.module('components', ['ngResource']);

Estoy usando un recurso para llenar la tabla y mi código de controlador es:

function Ajaxy($scope, $resource) {
//controller which has resource to populate the table 
}
Venkata Tata
fuente
1
¿La entrada está dentro de un formulario?
callmekatootie
1
no .. esta en una mesa !!
Venkata Tata

Respuestas:

808

Necesita agregar un directive, como este:

Javascript :

app.directive('myEnter', function () {
    return function (scope, element, attrs) {
        element.bind("keydown keypress", function (event) {
            if(event.which === 13) {
                scope.$apply(function (){
                    scope.$eval(attrs.myEnter);
                });

                event.preventDefault();
            }
        });
    };
});

HTML :

<div ng-app="" ng-controller="MainCtrl">
    <input type="text" my-enter="doSomething()">    
</div>
EpokK
fuente
77
@DerekAdair La directiva se une a los eventos keydowny keypressdel elemento al que se le atribuye. Cuando se recibe el evento, la expresión proporcionada se evalúa dentro de un $applybloque.
Pete Martin
77
Más seguro definir la clave de esta manera: var key = typeof event.which === "undefined" ? event.keyCode : event.which;siempre y cuando event.which no sea utilizado por todos los navegadores. Ver comentarios aquí: stackoverflow.com/a/4471635/2547632
Gabriel
3
También agregaría keyupen la prueba de enlace
user1713964
59
También tenga en cuenta que no se recomienda usar el prefijo ng, ya que esto puede entrar en conflicto con futuras directivas ng- *. Use el suyo en su lugar
Marius Balčytis
3
No olvides destruir tus enlaces: alcance. $ On ('$ destroy', function () {element.unbind ('keydown');})
nawlbergs
345

Una alternativa es usar la directiva estándar ng-keypress="myFunct($event)"

Luego, en su controlador puede tener:

...

$scope.myFunct = function(keyEvent) {
  if (keyEvent.which === 13)
    alert('I am an alert');
}

...
Chris Reynolds
fuente
18
Para guardar otras personas algún tiempo, ng-keypressno parece ser parte de 1.0.x angular, ui-keypress(con semántica ligeramente diferente de llamadas) está disponible sin embargo: angular-ui.github.io/ui-utils
Cebjyre
1
Creo que el comentario anterior fue dirigido a una respuesta diferente. (Solo como referencia.)
Cornelius
Martin esa es en realidad la función de un controlador: manejar eventos de UI.
Trevor de Koekkoek
55
Mejor aún, use ngKeypress y pase el evento $ a un filtro personalizado.
Martin
77
La mejor respuesta +1. ¿Por qué debería hacer mi propia directiva, si hay una, ya incluida en Angular?
bFunc
179

Mi enfoque más simple usando solo la directiva de construcción angular:

ng-keypress, ng-keydownO ng-keyup.

Por lo general, queremos agregar soporte de teclado para algo que ya se maneja con ng-click.

por ejemplo:

<a ng-click="action()">action</a>

Ahora, agreguemos soporte de teclado.

disparar con la tecla enter:

<a ng-click="action()" 
   ng-keydown="$event.keyCode === 13 && action()">action</a>

por tecla de espacio:

<a ng-click="action()" 
   ng-keydown="$event.keyCode === 32 && action()">action</a>

por espacio o tecla enter:

<a ng-click="action()" 
   ng-keydown="($event.keyCode === 13 || $event.keyCode === 32) && action()">action</a>

si estás en un navegador moderno

<a ng-click="action()" 
   ng-keydown="[13, 32].includes($event.keyCode) && action()">action</a>

Más información sobre keyCode:
keyCode está en desuso pero tiene una API bien admitida, en su lugar, puede usar $ evevt.key en el navegador compatible.
Ver más en https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key

Eric Chen
fuente
1
el secreto es el condicional antes del método a ejecutar $ event.which === 13 && action () - ¡gracias!
user12121234
1
'$ event.which' no funciona para mí, pero encontré '$ event.keyCode' que funciona.
Karl Adler
evento.que no está definido en IE <9 en keydown y keyup.
Eric Chen
2
"navegadores antiguos como IE9" ... nunca pensé que este día llegaría :)
Mihnea Belcin
1
¿Por qué nadie ha actualizado los fragmentos de código aquí para usar $ event.keyCode entonces? Lo editaría yo mismo, pero no puedo por alguna razón.
Nathan Hazzard el
102

Otra alternativa simple:

<input ng-model="edItem" type="text" 
    ng-keypress="($event.which === 13)?foo(edItem):0"/>

Y la alternativa ng-ui:

<input ng-model="edItem" type="text" ui-keypress="{'enter':'foo(edItem)'}"/>
Rodolfo Jorge Nemer Nogueira
fuente
99
ng-ui es ambiguo, en su lugar deberías decir "UI.Utils" o compartir el enlace: angular-ui.github.io/ui-utils
Paulo Oliveira
ui-utils parece estar en desuso
cafesanu
19

Esto es lo que descubrí cuando estaba creando una aplicación con un requisito similar, no requiere escribir una directiva y es relativamente simple decir lo que hace:

<input type="text" ng-keypress="($event.charCode==13)?myFunction():return" placeholder="Will Submit on Enter">
marcinzajkowski
fuente
3
Simple y efectivo.
Xplouder
15

Puede usar ng-keydown = "myFunction ($ event)" como atributo.

<input ng-keydown="myFunction($event)" type="number">

myFunction(event) {
    if(event.keyCode == 13) {   // '13' is the key code for enter
        // do what you want to do when 'enter' is pressed :)
    }
}
Fineas
fuente
5

html

<textarea id="messageTxt" 
    rows="5" 
    placeholder="Escriba su mensaje" 
    ng-keypress="keyPressed($event)" 
    ng-model="smsData.mensaje">
</textarea>

controller.js

$scope.keyPressed = function (keyEvent) {
    if (keyEvent.keyCode == 13) {
        alert('presiono enter');
        console.log('presiono enter');
    }
};
Jose Durley Lancheros
fuente
3

También puede aplicarlo a un controlador en un elemento padre. Este ejemplo se puede utilizar para resaltar una fila en una tabla presionando las teclas de flecha arriba / abajo.

app.controller('tableCtrl', [ '$scope', '$element', function($scope, $element) {
  $scope.index = 0; // row index
  $scope.data = []; // array of items
  $scope.keypress = function(offset) {
    console.log('keypress', offset);
    var i = $scope.index + offset;
    if (i < 0) { i = $scope.data.length - 1; }
    if (i >= $scope.data.length) { i = 0; }
  };
  $element.bind("keydown keypress", function (event) {
    console.log('keypress', event, event.which);
    if(event.which === 38) { // up
      $scope.keypress(-1);
    } else if (event.which === 40) { // down
      $scope.keypress(1);
    } else {
      return;
    }
    event.preventDefault();
  });
}]);


<table class="table table-striped" ng-controller="tableCtrl">
<thead>
    <tr>
        <th ng-repeat="(key, value) in data[0]">{{key}}</th>
    </tr>
</thead>
<tbody>
    <tr ng-repeat="row in data track by $index" ng-click="draw($index)" ng-class="$index == index ? 'info' : ''">
        <td ng-repeat="(key, value) in row">{{value}}</td>
    </tr>
</tbody>
</table>

Will Farrell
fuente
3

Molesto

ng-keypress="console.log($event)"
ng-keypress="alert(123)"

no hizo nada por mi

Estrangular la muestra en https://docs.angularjs.org/api/ng/directive/ngKeypress , que hace ng-keypress = "count = count + 1", funciona.

Encontré una solución alternativa, que al presionar Enter invoca el botón ng-click del botón.

<input ng-model="..." onkeypress="if (event.which==13) document.getElementById('button').click()"/>
<button id="button" ng-click="doSomething()">Done</button>
Snaran
fuente
ng-keypress="console.log('foo')"tampoco funcionó para mí, pero si lo hace ng-keypress="fooMethod()"y en su controlador $scope.fooMethod = function() { console.log('fooMethod called'); }funciona.
GraehamF
3
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
Informe your name:<input type="text" ng-model="pergunta" ng-keypress="pressionou_enter($event)" ></input> 
<button ng-click="chamar()">submit</button>
<h1>{{resposta}}</h1> 
</div>
<script>
var app = angular.module('myApp', []);
//create a service mitsuplik
app.service('mitsuplik', function() {
    this.myFunc = function (parametro) {
        var tmp = ""; 
        for (var x=0;x<parametro.length;x++)
            {
            tmp = parametro.substring(x,x+1) + tmp;
            } 
        return tmp;
    }
});
//Calling our service
app.controller('myCtrl', function($scope, mitsuplik) { 
  $scope.chamar = function() { 
        $scope.resposta = mitsuplik.myFunc($scope.pergunta); 
    };
  //if mitsuplik press [ENTER], execute too
  $scope.pressionou_enter = function(keyEvent) {
             if (keyEvent.which === 13) 
                { 
                $scope.chamar();
                }

    }
});
</script>
</body>
</html>
Marcus Poli
fuente
2

Esta es una extensión de la respuesta de EpokK.

Tuve el mismo problema de tener que llamar a una función de alcance cuando enter se presiona en un campo de entrada. Sin embargo, también quería pasar el valor del campo de entrada a la función especificada. Esta es mi solución:

app.directive('ltaEnter', function () {
return function (scope, element, attrs) {
    element.bind("keydown keypress", function (event) {
        if(event.which === 13) {
          // Create closure with proper command
          var fn = function(command) {
            var cmd = command;
            return function() {
              scope.$eval(cmd);
            };
          }(attrs.ltaEnter.replace('()', '("'+ event.target.value +'")' ));

          // Apply function
          scope.$apply(fn);

          event.preventDefault();
        }
    });
};

});

El uso en HTML es el siguiente:

<input type="text" name="itemname" lta-enter="add()" placeholder="Add item"/>

Felicitaciones a EpokK por su respuesta.

tassaert.l
fuente
<input type="text" name="itemname" ng-model="item.itemname" lta-enter="add(item.itemname)" placeholder="Add item"/>
aycanadal
1

¿Qué hay de esto ?:

<form ng-submit="chat.sendMessage()">
    <input type="text" />
    <button type="submit">
</form>

Ahora, cuando presiona la tecla Intro después de escribir algo en su entrada, el formulario sabe cómo manejarlo.

juanmorschrott
fuente
Cómo / dónde se chat.sendMessage()define
Aaron McMillin
0

Algún ejemplo de código que hice para mi proyecto. Básicamente agrega etiquetas a su entidad. Imagina que has ingresado texto, al ingresar el nombre de la etiqueta obtienes un menú desplegable con etiquetas precargadas para elegir, navegas con flechas y seleccionas con Enter:

HTML + AngularJS v1.2.0-rc.3

    <div>
        <form ng-submit="addTag(newTag)">
            <input id="newTag" ng-model="newTag" type="text" class="form-control" placeholder="Enter new tag"
                   style="padding-left: 10px; width: 700px; height: 33px; margin-top: 10px; margin-bottom: 3px;" autofocus
                   data-toggle="dropdown"
                   ng-change="preloadTags()"
                   ng-keydown="navigateTags($event)">
            <div ng-show="preloadedTags.length > 0">
                <nav class="dropdown">
                    <div class="dropdown-menu preloadedTagPanel">
                        <div ng-repeat="preloadedTag in preloadedTags"
                             class="preloadedTagItemPanel"
                             ng-class="preloadedTag.activeTag ? 'preloadedTagItemPanelActive' : '' "
                             ng-click="selectTag(preloadedTag)"
                             tabindex="{{ $index }}">
                            <a class="preloadedTagItem"
                               ng-class="preloadedTag.activeTag ? 'preloadedTagItemActive' : '' "
                               ng-click="selectTag(preloadedTag)">{{ preloadedTag.label }}</a>
                        </div>
                    </div>
                </nav>
            </div>
        </form>
    </div>

Controller.js

$scope.preloadTags = function () {
    var newTag = $scope.newTag;
    if (newTag && newTag.trim()) {
        newTag = newTag.trim().toLowerCase();

        $http(
            {
                method: 'GET',
                url: 'api/tag/gettags',
                dataType: 'json',
                contentType: 'application/json',
                mimeType: 'application/json',
                params: {'term': newTag}
            }
        )
            .success(function (result) {
                $scope.preloadedTags = result;
                $scope.preloadedTagsIndex = -1;
            }
        )
            .error(function (data, status, headers, config) {
            }
        );
    } else {
        $scope.preloadedTags = {};
        $scope.preloadedTagsIndex = -1;
    }
};

function checkIndex(index) {
    if (index > $scope.preloadedTags.length - 1) {
        return 0;
    }
    if (index < 0) {
        return $scope.preloadedTags.length - 1;
    }
    return index;
}

function removeAllActiveTags() {
    for (var x = 0; x < $scope.preloadedTags.length; x++) {
        if ($scope.preloadedTags[x].activeTag) {
            $scope.preloadedTags[x].activeTag = false;
        }
    }
}

$scope.navigateTags = function ($event) {
    if (!$scope.newTag || $scope.preloadedTags.length == 0) {
        return;
    }
    if ($event.keyCode == 40) {  // down
        removeAllActiveTags();
        $scope.preloadedTagsIndex = checkIndex($scope.preloadedTagsIndex + 1);
        $scope.preloadedTags[$scope.preloadedTagsIndex].activeTag = true;
    } else if ($event.keyCode == 38) {  // up
        removeAllActiveTags();
        $scope.preloadedTagsIndex = checkIndex($scope.preloadedTagsIndex - 1);
        $scope.preloadedTags[$scope.preloadedTagsIndex].activeTag = true;
    } else if ($event.keyCode == 13) {  // enter
        removeAllActiveTags();
        $scope.selectTag($scope.preloadedTags[$scope.preloadedTagsIndex]);
    }
};

$scope.selectTag = function (preloadedTag) {
    $scope.addTag(preloadedTag.label);
};

CSS + Bootstrap v2.3.2

.preloadedTagPanel {
    background-color: #FFFFFF;
    display: block;
    min-width: 250px;
    max-width: 700px;
    border: 1px solid #666666;
    padding-top: 0;
    border-radius: 0;
}

.preloadedTagItemPanel {
    background-color: #FFFFFF;
    border-bottom: 1px solid #666666;
    cursor: pointer;
}

.preloadedTagItemPanel:hover {
    background-color: #666666;
}

.preloadedTagItemPanelActive {
    background-color: #666666;
}

.preloadedTagItem {
    display: inline-block;
    text-decoration: none;
    margin-left: 5px;
    margin-right: 5px;
    padding-top: 5px;
    padding-bottom: 5px;
    padding-left: 20px;
    padding-right: 10px;
    color: #666666 !important;
    font-size: 11px;
}

.preloadedTagItem:hover {
    background-color: #666666;
}

.preloadedTagItemActive {
    background-color: #666666;
    color: #FFFFFF !important;
}

.dropdown .preloadedTagItemPanel:last-child {
    border-bottom: 0;
}
Dmitri Algazin
fuente
2
Creo que esta es una solución desagradable. Un controlador no debe manejar cosas de la interfaz de usuario como presionar teclas.
Maya Kathrine Andersen
55
Esta respuesta contiene mucho "ruido", como una manera de hablar, que contiene mucho marcado que, por lo que puedo ver a simple vista, no se relaciona con la pregunta real en cuestión. Puede ser más sucinto / útil condensar el código en la respuesta y proporcionar el ejemplo completo en un gist / jsfiddle / plnkr.
Cornelius
1
@MartinAndersen, ¿dónde se debe manejar una pulsación de tecla en una aplicación angular?
Emanegux
1
Cuando lo miro ahora se ve bien. Básicamente, es cómo las pulsaciones de teclas siempre se han manejado con el modelo de evento JS.
Maya Kathrine Andersen
0

Llego un poco tarde ... pero encontré una solución más simple usando auto-focus... Esto podría ser útil para botones u otros cuando aparece un dialog:

<button auto-focus ng-click="func()">ok</button>

Eso debería estar bien si desea presionar el botón onEspacio o Entrar clics.

Abdellah Alaoui
fuente
la pregunta es sobre presionar enter y hacer algo.
BlaShadow
0

Aquí está mi directiva:

mainApp.directive('number', function () {
    return {
        link: function (scope, el, attr) {
            el.bind("keydown keypress", function (event) {
                //ignore all characters that are not numbers, except backspace, delete, left arrow and right arrow
                if ((event.keyCode < 48 || event.keyCode > 57) && event.keyCode != 8 && event.keyCode != 46 && event.keyCode != 37 && event.keyCode != 39) {
                    event.preventDefault();
                }
            });
        }
    };
});

uso:

<input number />
WtFudgE
fuente
0

puede usar ng-keydown, ng-keyup, ng-press como este.

para activar una función:

   <input type="text" ng-keypress="function()"/>

o si tiene una condición como cuando presiona escape (27 es el código clave para escapar)

 <form ng-keydown=" event.which=== 27?cancelSplit():0">
....
</form>
Eassa Nassar
fuente
0

Creo que usar document.bind es un poco más elegante

constructor($scope, $document) {
  var that = this;
  $document.bind("keydown", function(event) {
    $scope.$apply(function(){
      that.handleKeyDown(event);
    });
  });
}

Para llevar el documento al constructor del controlador:

controller: ['$scope', '$document', MyCtrl]
FreshPow
fuente
0
(function(angular) {
  'use strict';
angular.module('dragModule', [])
  .directive('myDraggable', ['$document', function($document) {
    return {
      link: function(scope, element, attr) {
         element.bind("keydown keypress", function (event) {
           console.log('keydown keypress', event.which);
            if(event.which === 13) {
                event.preventDefault();
            }
        });
      }
    };
  }]);
})(window.angular);
Mukundhan
fuente
0

Todo lo que necesita hacer para obtener el evento es lo siguiente:

console.log(angular.element(event.which));

Una directiva puede hacerlo, pero no es así como lo hace.

Konkret
fuente