Enviar cuadro de diálogo jQuery UI en <Enter>

131

Tengo un cuadro de diálogo jQuery UI con un formulario. Me gustaría simular un clic en uno de los botones del cuadro de diálogo para que no tenga que usar el mouse o la pestaña. En otras palabras, quiero que actúe como un cuadro de diálogo GUI normal donde simula presionar el botón "Aceptar".

Supongo que esta podría ser una opción simple con el cuadro de diálogo, pero no puedo encontrarla en la documentación de jQuery UI . Podría vincular cada entrada de formulario con keyup () pero no sabía si había una forma más simple / limpia. Gracias.

CMB
fuente
Si desea evitar el uso de un formulario y desea un código reutilizable, he proporcionado una buena respuesta aquí: stackoverflow.com/a/9628800/329367
Darren

Respuestas:

153

No sé si hay una opción en el widget jQuery UI , pero podría simplemente vincular el keypressevento al div que contiene su diálogo ...

$('#DialogTag').keypress(function(e) {
    if (e.keyCode == $.ui.keyCode.ENTER) {
          //Close dialog and/or submit here...
    }
});

Esto se ejecutará sin importar qué elemento tenga el foco en su diálogo, lo que puede o no ser bueno dependiendo de lo que desee.

Si desea que esta sea la funcionalidad predeterminada, puede agregar este código:

// jqueryui defaults
$.extend($.ui.dialog.prototype.options, { 
    create: function() {
        var $this = $(this);

        // focus first button and bind enter to it
        $this.parent().find('.ui-dialog-buttonpane button:first').focus();
        $this.keypress(function(e) {
            if( e.keyCode == $.ui.keyCode.ENTER ) {
                $this.parent().find('.ui-dialog-buttonpane button:first').click();
                return false;
            }
        });
    } 
});

Aquí hay una vista más detallada de cómo se vería:

$( "#dialog-form" ).dialog({
  buttons: {  },
  open: function() {
    $("#dialog-form").keypress(function(e) {
      if (e.keyCode == $.ui.keyCode.ENTER) {
        $(this).parent().find("button:eq(0)").trigger("click");
      }
    });
  };
});
Casey Williams
fuente
2
No importa, lo encontré: agregue "abrir" al diálogo (como cerrar, modal, bgiframe, etc.) y conecte el controlador de teclado allí.
Milan Babuškov
55
Para Webkit (Safari / Chrome), esto solo funciona si hago "keydown" en lugar de "keyup". No estoy seguro de si se trata de un cambio reciente o si es importante que mi página también tenga una forma real. Aún así, gracias por el consejo!
Nicholas Piasecki
12
En lugar de if (e.keyCode == 13) podría hacer if (e.keyCode === $ .ui.keyCode.ENTER) para aumentar la legibilidad.
A. Murray
2
Voté por esta respuesta. Si bien es breve y ordenado, en Firefox 7.0.1 esto también activará su botón "Aceptar" si el usuario selecciona algo del cuadro desplegable de autocompletar, por ejemplo, una dirección de correo electrónico previamente ingresada.
cburgmer
2
Es una mala idea unirse a eventos en "open:". Esto hará que se vuelva a vincular cada vez que se abra el cuadro de diálogo, lo que significa que si el cuadro de diálogo se abre dos veces, el controlador de eventos se llamará dos veces.
Elezar
67

He resumido las respuestas anteriores y he agregado cosas importantes

$(document).delegate('.ui-dialog', 'keyup', function(e) {
        var target = e.target;
        var tagName = target.tagName.toLowerCase();

        tagName = (tagName === 'input' && target.type === 'button') 
          ? 'button' 
          : tagName;

        isClickableTag = tagName !== 'textarea' && 
          tagName !== 'select' && 
          tagName !== 'button';

        if (e.which === $.ui.keyCode.ENTER && isClickableTag) {
            $(this).find('.ui-dialog-buttonset button').eq(0).trigger('click');

            return false;
        }
    });

Ventajas:

  1. No permitir la tecla enter en elementos no compatibles como textarea, select, buttono entradas con botón de tipo, imagina usuario haga clic en entrartextarea y obtener el formulario enviado en lugar de obtener nueva línea!
  2. El enlace se realiza una vez, evite usar la devolución de llamada de diálogo 'abrir' para vincular la tecla enter para evitar vincular la misma función una y otra vez cada vez que el diálogo se 'abre'
  3. Evite cambiar el código existente como algunas respuestas anteriores sugieren
  4. Use 'delegar' en lugar del obsoleto 'en vivo' y evite usar el nuevo método 'encendido' para permitir trabajar con versiones anteriores de jquery
  5. Debido a que usamos delegado, eso significa que el código anterior se puede escribir incluso antes de inicializar el diálogo. también puedes ponerlo en la etiqueta de la cabeza incluso sin$(document).ready
  6. Además, el delegado vinculará solo un controlador documenty no lo vinculará a cada cuadro de diálogo como en algunos de los códigos anteriores, para una mayor eficiencia
  7. Funciona incluso con diálogos generados dinámicamente como $('<div><input type="text"/></div>').dialog({buttons: .});
  8. Trabajado con ie 7/8/9!
  9. Evite usar el selector lento :first
  10. Evite usar hacks como en las respuestas aquí para hacer un botón de envío oculto

Desventajas

  1. Ejecute el primer botón como predeterminado, puede elegir otro botón con eq() o llamar a una función dentro de la instrucción if
  2. Todos los cuadros de diálogo tendrán el mismo comportamiento que puede filtrar haciendo que su selector sea más específico, es decir, '#dialog' en lugar de '.ui-dialog'

Sé que la pregunta es antigua pero he tenido la misma necesidad, así que compartí la solución que he usado.

Basemm
fuente
44
El hecho de que esta no sea la respuesta aceptada y no tenga más votos me entristece, es muy informativo y no agrega controladores continuamente. +1
Chris O'Kelly
1
excelente respuesta, tener la devolución de llamada abierta para agregar enlaces es algo que desea evitar
Jay Rizzi
1
para mí esto funciona cuando el evento es keydown y elimino todas las condiciones de tagName y
elimino el
1
También tuve que cambiar a "keydown" para que esto funcionara (probado en OS X 10.8.4, Chrome 29 y Firefox 23).
natebeaty
1
Dado que esta es una respuesta anterior, vale la pena señalar que .delegate()fue obsoleta en jQuery 3.0, por lo que .on()(disponible desde 1.7) es probablemente la ruta a seguir en este punto.
jinglesthula
13
$('#dialogBox').dialog('open');
$('.ui-dialog-buttonpane > button:last').focus();

Funciona perfectamente con la última versión de JQuery UI (1.8.1). También puede usar: primero en lugar de: último, según el botón que desee establecer como predeterminado.

Esta solución, en comparación con la anterior seleccionada, tiene la ventaja de mostrar qué botón es el predeterminado para el usuario. El usuario también puede pulsar TAB entre los botones y presionar ENTER hará clic en el botón actualmente bajo foco.

Salud.

Mario Awad
fuente
¿Y qué pasa si su diálogo tiene uno o más campos de entrada de texto? Quiero que ENTER envíe el cuadro de diálogo de inicio de sesión cuando el usuario se encuentre en los campos de nombre de usuario y contraseña.
David Harkness
1
@David si está utilizando los botones de diálogo de jQuery, simplemente oculte el botón de envío de entrada normal en el formulario. p.ej. visibilidad: oculta;
Damo
6

Una forma cruda pero efectiva de hacer que esto funcione de manera más genérica:

$.fn.dlg = function(options) {
    return this.each(function() {
             $(this).dialog(options);
             $(this).keyup(function(e){
                  if (e.keyCode == 13) {                
                       $('.ui-dialog').find('button:first').trigger('click');
                  }
             });
    });
}

Luego, cuando crea un nuevo cuadro de diálogo, puede hacer esto:

$('#a-dialog').mydlg({...options...})

Y úselo como un diálogo jquery normal a partir de entonces:

$('#a-dialog').dialog('close')

Hay maneras de mejorar eso para que funcione en casos más especiales. Con el código anterior, elegirá automáticamente el primer botón del cuadro de diálogo como el botón que se activará cuando se presione Intro. También se supone que solo hay un diálogo activo en un momento dado, lo que puede no ser el caso. Pero se entiende la idea.

Nota: Como se mencionó anteriormente, el botón que se presiona al ingresar depende de su configuración. Por lo tanto, en algunos casos querrá usar el: primer selector en el método .find y en otros puede usar el: último selector.

Karim
fuente
Creo que debería haber un .first () allí como en $ ('. Ui-dialog'). Find ('button'). First (). Trigger ('click'); De lo contrario, activará el clic de todos los botones del cuadro de diálogo si hay más de uno.
JustinStolle
@thejh: No, adjunta un controlador de eventos de keyup a cada cuadro de diálogo, pero solo el cuadro de diálogo que contiene el elemento con foco cuando se presiona la tecla recibirá el evento.
David Harkness
6

En lugar de escuchar códigos clave como en esta respuesta (que no pude poner a trabajar), puede vincular el evento de envío del formulario dentro del diálogo y luego hacer esto:

$("#my_form").parents('.ui-dialog').first().find('.ui-button').first().click();

Entonces, todo se vería así

$("#my_form").dialog({
  open: function(){
    //Clear out any old bindings
    $("#my_form").unbind('submit');
    $("#my_form").submit(function(){
      //simulate click on create button
      $("#my_form").parents('.ui-dialog').first().find('.ui-button').first().click();
      return false;
    });
  },
  buttons: {
    'Create': function() {
      //Do something
    },
    'Cancel': function() {
      $(this).dialog('close');
    }
  }
});

Tenga en cuenta que diferentes navegadores manejan la tecla enter de manera diferente, y algunos no siempre hacen un envío al ingresar.

Salida Software
fuente
Esta parece ser la respuesta más elegante.
Dan
Esto no funciona cuando tengo tres o más entradas en el mismo cuadro de diálogo. No se porque.
programado el
6

Ben Clayton es el más limpio y corto y se puede colocar en la parte superior de la página de índice antes de que se inicialicen los cuadros de diálogo de jquery. Sin embargo, me gustaría señalar que ".live" ha quedado en desuso. La acción preferida ahora es ".on". Si desea que ".on" funcione como ".live", deberá usar eventos delegados para adjuntar el controlador de eventos. Además, algunas otras cosas ...

  1. Prefiero usar el método ui.keycode.ENTER para probar la tecla enter ya que no tiene que recordar el código de la llave real.

  2. El uso de "$ ('. Ui-dialog-buttonpane button: first', $ (this))" para el selector de clics hace que todo el método sea genérico.

  3. Desea agregar "return false;" para evitar el incumplimiento y detener la propagación.

En este caso...

$('body').on('keypress', '.ui-dialog', function(event) { 
    if (event.keyCode === $.ui.keyCode.ENTER) { 
        $('.ui-dialog-buttonpane button:first', $(this)).click();
        return false;
    }
});
Nelson M
fuente
4

No sé más simple, pero normalmente rastrearías qué botón tiene el foco actual. Si el foco se cambia a un control diferente, entonces el "foco del botón" permanecería en el botón que tenía el foco al último. Normalmente, el "foco del botón" comenzaría en su botón predeterminado. Tocar un botón diferente cambiaría el "foco del botón". Tendría que decidir si navegar a un elemento de formulario diferente restablecería el "foco del botón" al botón predeterminado nuevamente. Probablemente también necesitará algún indicador visual que no sea el predeterminado del navegador para indicar el botón enfocado, ya que pierde el enfoque real en la ventana.

Una vez que tenga la lógica de enfoque del botón desactivada e implementada, entonces probablemente agregaría un controlador de teclas al cuadro de diálogo e invocaría la acción asociada con el botón actualmente "enfocado".

EDITAR : Supongo que desea poder presionar enter cada vez que complete elementos de formulario y tenga prioridad la acción del botón "actual". Si solo desea este comportamiento cuando el botón está realmente enfocado, mi respuesta es demasiado complicada.

tvanfosson
fuente
3

Encontré esta solución, funciona en IE8, Chrome 23.0 y Firefox 16.0

Se basa en el comentario de Robert Schmidt.

$("#id_dialog").dialog({
    buttons: [{
        text: "Accept",
        click: function() {
            // My function
        },
        id: 'dialog_accept_button'
    }]
}).keyup(function(e) {
    if (e.keyCode == $.ui.keyCode.ENTER)
        $('#dialog_accept_button').click();
});

Espero que ayude a cualquiera.

Pablo Oña
fuente
¡Gracias! ¡Eso me ahorró mucho tiempo! :)
Rahul Desai
3

A veces olvidamos lo fundamental de lo que el navegador ya admite:

<input type="submit" style="visibility:hidden" />

Esto hará que la ENTERclave envíe el formulario.

Seifu
fuente
2

Lo hice así ...;) Espero que sea útil para alguien ...

$(window).keypress(function(e) {
    if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
        $(".ui-dialog:visible").find('.ui-dialog-buttonpane').find('button:first').click();
        return false;
    }
});
Stanislav Vychegzhanin
fuente
2

Esto debería funcionar para activar el clic del controlador de clic del botón. Este ejemplo supone que ya ha configurado el formulario en el cuadro de diálogo para utilizar el complemento jquery.validate. pero podría adaptarse fácilmente.

open: function(e,ui) {
    $(this).keyup(function(e) {
        if (e.keyCode == 13) {
           $('.ui-dialog-buttonpane button:last').trigger('click');
        }
    });
},
buttons: {
    "Submit Form" : function() {
            var isValid = $('#yourFormsID').valid();
            // if valid do ajax call
            if(isValid){
               //do  your ajax call here. with serialize form or something...

            }
}
timbrown
fuente
1

Me doy cuenta de que ya hay muchas respuestas, pero creo que, naturalmente, mi solución es la más perfecta y posiblemente la más corta. Tiene la ventaja de que funciona en cualquier diálogo creado en cualquier momento en el futuro.

$(".ui-dialog").live("keyup", function(e) {
    if (e.keyCode === 13) {
        $('.ok-button', $(this) ).first().click();
    }
});
Ben Clayton
fuente
1
Hola, gracias por actualizar, solo una pequeña pregunta, ¿qué es "botón .ok" aquí? ¿es la clase que tiene que aplicar en el botón predeterminado en el que desea hacer clic con enter?
UID
Lo siento si encuentra la pregunta tontamente ... soy demasiado nuevo en JS / jQuery
UID
@BenClayton: esta respuesta podría mejorarse si la pusiera en el contexto de jQueryUI Dialog.
Michael Potter
1

Aquí esta lo que hice:

myForm.dialog({
  "ok": function(){
    ...blah...
  }
  Cancel: function(){
    ...blah...
  }
}).keyup(function(e){
  if( e.keyCode == 13 ){
   $(this).parent().find('button:nth-child(1)').trigger("click");
  }
});

En este caso, myForm es un objeto jQuery que contiene el html del formulario (nota, no hay etiquetas de "formulario" allí ... si las coloca en la pantalla completa se actualizará cuando presione "enter").

Cada vez que el usuario presiona "enter" dentro del formulario, será el equivalente a hacer clic en el botón "ok".

Esto también evita el problema de tener el formulario abierto con el botón "ok" ya resaltado. Si bien eso sería bueno para formularios sin campos, si necesita que el usuario complete los datos, entonces probablemente desee que se resalte el primer campo.

Tyler
fuente
Esta es la solución más lógica. Aún mejor si declara su botón con una identificación y pasa el selector a find () pero de cualquier manera funciona. +1
Vincent
1

hecho y hecho

  $('#login input').keyup(function(e) {
      if (e.keyCode == 13) {
          $('#login form').submit();
      }
   }
Kevin
fuente
0

si conoce el selector de elemento de botón:

$('#dialogBox').dialog('open');
$('#okButton').focus();

Debería hacer el truco por ti. Esto enfocará el botón ok, y enter lo 'hará clic', como era de esperar. Esta es la misma técnica utilizada en los diálogos nativos de la interfaz de usuario.

sandesh247
fuente
0
   $("#LogOn").dialog({
       modal: true,
       autoOpen: false,
       title: 'Please Log On',
       width: 370,
       height: 260,
       buttons: { "Log On": function () { alert('Hello world'); } },
       open: function() { $(this).parents('.ui-dialog-buttonpane button:eq(0)').focus();}
   });
LeCram
fuente
0

Encontré una solución bastante simple para este problema:

var d = $('<div title="My dialog form"><input /></div>').dialog(
    buttons: [{
        text: "Ok",
        click: function(){
            // do something
            alert('it works');
        },
        className: 'dialog_default_button'
    }]
});

$(d).find('input').keypress(function(e){
    if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
        e.preventDefault();
        $('.dialog_default_button').click();
    }
});
Robert Schmidt
fuente
0
$('#DialogID').dialog("option", "buttons")["TheButton"].apply()

Esto funciono muy bien para mi..

Peter
fuente
Haría bien en incluir una referencia a $ ('# DialogID'). Dialog () como argumento para aplicar. De lo contrario, $ (this) .close () no tendrá el contexto correcto dentro de TheButton.
Dave el
0

Ninguna de estas soluciones parecía funcionar para mí en IE9. Terminé con esto ...

$('#my-dialog').dialog({
    ...
    open: function () {
        $(this).parent()
               .find("button:eq(0)")
               .focus()
               .keyup(function (e) {
                   if (e.keyCode == $.ui.keyCode.ENTER) {
                       $(this).trigger("click");
                   };
               });
    }
});
Paul Martin
fuente
0

Debajo del cuerpo se usa porque el diálogo DIV agregado en el cuerpo, por lo que el cuerpo ahora escucha el evento del teclado. Probó en IE8,9,10, Mojila, Chrome.

open: function() {
$('body').keypress(function (e) { 
     if (e.keyCode == 13) {   
     $(this).parent().find(".ui-dialog-buttonpane button:eq(0)").trigger("click");
     return false; 
     }
  }); 
}
LoopCoder
fuente
0

Porque no tengo suficiente reputación para publicar comentarios.

$(document).delegate('.ui-dialog', 'keyup', function(e) {
  var tagName = e.target.tagName.toLowerCase();

  tagName = (tagName === 'input' && e.target.type === 'button') ? 'button' : tagName;

  if (e.which === $.ui.keyCode.ENTER && tagName !== 'textarea' && tagName !== 'select' && tagName !== 'button') {
      $(this).find('.ui-dialog-buttonset button').eq(0).trigger('click');
    return false;
  } else if (e.which === $.ui.keyCode.ESCAPE) {
      $(this).close();
  }
});

La respuesta modificada de Basemm # 35 también agrega Escape para cerrar el diálogo.

Liam Mitchell
fuente
-1

Funciona bien ¡Gracias!

open: function () { debugger; $("#dialogDiv").keypress(function (e) { if (e.keyCode == 13) { $(this).parent().find("#btnLoginSubmit").trigger("click"); } }); },

Durgaprasad Katari
fuente
hmm ... ¿hay algo nuevo (en comparación con las respuestas anteriores) en tu publicación?
kleopatra
-1

Dale clases a tus botones y selecciónalos de la manera habitual:

$('#DialogTag').dialog({
  closeOnEscape: true,
  buttons: [
    {
      text: 'Cancel',
      class: 'myCancelButton',
      click: function() {
        // Close dialog fct
      }
    },
    {
      text: 'Ok',
      class: 'myOKButton',
      click: function() {
        // OK fct
      }
    }
  ],
  open: function() {

    $(document).keyup(function(event) {

      if (event.keyCode === 13) {
        $('.myOKButton').click();
      }

    });

  }
});
yPhil
fuente