Formulario con varios botones. Implementación usable y accesible
Artículos relacionados
[24-07-07] Enlaces que actúan como botones. Implementación accesible.
[28-02-08] Formularios usables: 60 Directrices de Usabilidad
[28-03-12] Detectar si una imagen se ha cargado. Descripción extensa de una imagen: accesible con lector de pantalla y visible sin imágenes activas
Imagina que tenemos que realizar un formulario muy sencillo:
El formulario consta de un campo NIF de tipo texto y tres botones que realizan tres operativas diferentes: "Crear usuario", "Eliminar usuario" y "Cancelar".
No parece muy complicado ¿verdad? De hecho existen muchas formas de implementarlo; el problema es que la mayoría de ellas son inaccesibles.
El objetivo de este artículo es explicar qué implementaciones son posibles y clasificarlas en:
NO accesible/NO nos sirve
Accesible/Nos sirve pero NO es recomendable
Accesible y recomendable ¡bingo! ¡usémoslo!
Nota: no entraremos en discusiones acerca de si la operativa de "Crear Usuario" y "Eliminar Usuario" deberían ser dos páginas diferentes, con un único botón "Aceptar", etc. Es un ejemplo para ilustrar el problema de los formularios con varios botones.
Implementar la acción por Javascript
Clasificación:NO accesible/NO nos sirve
Un desarrollador novato (llamémosle Hugo) saldrá del paso de la siguiente manera:
<input type="button"
value="Crear usuario"
id="nuevo"
name="nuevo"
onclick= "document.form1.action = 'nuevo.jsp';
document.form1.submit()" />
<input type="button"
value="Eliminar usuario"
id="eliminar"
name="eliminar"
onclick= "document.form1.action = 'eliminar.jsp';
document.form1.submit()" />
<input type="button"
value="Cancelar"
id="cancelar"
name="cancelar"
onclick= "self.location.href = 'principal.jsp'" />
Si tenemos suerte y a Hugo se le ha estropeado el ratón, pulirá su código así:
<input type="button" value="Crear usuario" id="nuevo" name="nuevo" onclick="document.form1.action = 'nuevo.jsp'; document.form1.submit()" onkeypress="document.form1.action = 'nuevo.jsp'; document.form1.submit()" /> <input type="button" value="Eliminar usuario" id="eliminar" name="eliminar" onclick="document.form1.action = 'eliminar.jsp'; document.form1.submit()" onkeypress="document.form1.action = 'eliminar.jsp'; document.form1.submit()" /> <input type="button" value="Cancelar" id="cancelar" name="cancelar" onclick="self.location.href = 'principal.jsp'" onkeypress= "self.location.href = 'principal.jsp'" />
Posiblemente Hugo, en un momento de lucidez, comprenda que si el primer botón es de tipo "submit", se convertirá en el botón por defecto, el que se ejecute al pulsar "intro" y además se ahorra una función.
Gracias a ello, un usuario que tenga desactivado el javascript o su user-agent no lo admita, al menos podrá crear un usuario:
<form action="nuevo.jsp" name="form1" id="form1" method="post"> [...] <input type="submit" value="Crear usuario" id="nuevo" name="nuevo" /> <input type="button" value="Eliminar usuario" id="eliminar" name="eliminar" onclick="document.form1.action = 'eliminar.jsp'; document.form1.submit()" onkeypress="document.form1.action = 'eliminar.jsp'; document.form1.submit()" /> <input type="button" value="Cancelar" id="cancelar" name="cancelar" onclick="self.location.href = 'principal.jsp'" onkeypress="self.location.href = 'principal.jsp'" />
Si Hugo tiene muchos formularios, terminará descubriendo las funciones javascript y limpiando su código:
<script type="text/javascript"> <![CDATA[ function someter(id){ document.form1.action=id; document.form1.submit(); } function navegar(id){ self.location.href=id; } ]]> </script> [...] <form action="nuevo.jsp" name="form1" id="form1" method="post"> [...] <input type="submit" value="Crear usuario" id="nuevo" name="nuevo" /> <input type="button" value="Eliminar usuario" id="eliminar" name="eliminar" onclick="someter('eliminar.jsp')" onkeypress="someter('eliminar.jsp')" /> <input type="button" value="Cancelar" id="cancelar" name="cancelar" onclick="navegar('principal.jsp')" onkeypress="navegar('principal.jsp')" />
Si Hugo asiste a un cursillo básico acerca de las bondades de separar la presentación, del contenido y de la programación, entonces quizás tengamos la suerte de ver javascript no-intrusivo:
[en el fichero funciones.js] function init(){ document.getElementById("eliminar").onclick = function(){ document.form1.action= "eliminar.jsp"; document.form1.submit(); } document.getElementById("eliminar").onkeypress = function(){ document.form1.action= "eliminar.jsp"; document.form1.submit(); } document.getElementById("cancelar").onclick = function() { self.location.href="navegar.jsp"; } document.getElementById("cancelar").onkeypress = function() { self.location.href="navegar.jsp"; } } window.onload=init; [en la página] <form action="nuevo.jsp" name="form1" id="form1" method="post"> [...] <input type="submit" value="Crear usuario" id="nuevo" name="nuevo" /> <input type="button" value="Eliminar usuario" id="eliminar" name="eliminar" /> <input type="button" value="Cancelar" id="cancelar" name="cancelar" />
En fin, podríamos seguir mejorando y depurando el código o poner otras alternativas similares que se ven a menudo, por ejemplo ir cambiando dinámicamente por javascript un campo "hidden" donde se guarda el destino final de la página, y mediante el evento "onsubmit" del formulario cambiar el "action" del formulario, etc.
Pero todas ellas nos llevarán a un callejón sin salida, porque un usuario que no tenga activado el javascript o su user-agent no admita javascript, en el mejor de los casos podrá ejecutar sólo la acción "Crear Usuario".
Varios formularios
Clasificación:NO accesible/NO nos sirve
Hugo le ha pedido ayuda a Pedro, quien después de pensar un rato ha tenido una idea genial: hagamos que todos los botones sean de tipo "submit" y para evitar tener que modificar por javascript el "action" del formulario, ¡hagamos varios formularios!. Dicho y hecho.
Lo primero que se les ocurre es encerrar cada botón en un formulario:
<form name="form1" [...]
<input type="submit" [...]
</form>
<form name="form2" [...]
<input type="submit" [...]
</form>
<form name="form3" [...]
<input type="submit" [...]
</form>
Pronto se dan cuenta de que esto no lleva a ninguna parte porque el campo de texto NIF no está dentro del formulario y no se enviará su contenido con el "submit".
Pedro, que no se rinde fácilmente, decide que lo que hay que hacer es anidar los formularios:
<form name="form1" [...]
<form name="form2" [...]
<form name="form3" [...]
[aquí nuestro campo de texto NIF]
<input type="submit" [...]
</form>
<input type="submit" [...]
</form>
<input type="submit" [...]
</form>
Pedro y Hugo comprueban que esto no funciona... lástima, no se pueden anidar formularios.
Alternativa accesible con <noscript>
Clasificación:Accesible/Nos sirve pero NO es recomendable
Hugo y Pedro recuerdan que Lisa hizo un curso de accesibilidad y le piden consejo. Ella lo ve claro: "utilicemos la etiqueta <noscript>
". Lisa se pone de inmediato a teclear, añadiendo al final del código que vimos en el primer apartado el siguiente <noscript>
:
<form action="nuevo.jsp"
name="form1"
id="form1"
method="post">
[...]
<input type="submit"
value="Crear usuario"
id="nuevo"
name="nuevo" />
<input type="button"
value="Eliminar usuario"
id="eliminar"
name="eliminar" />
<input type="button"
value="Cancelar"
id="cancelar"
name="cancelar" />
</form>
<noscript>
<p>Su navegador no admite javascript.</p>
<ul><li>Para crear un nuevo usuario pulse el botón
"Crear usuario" del formulario anterior</li>
<li>Para cancelar y volver a la página anterior
pulse el siguiente enlace:
<a href="principal.jsp">Cancelar</a></li>
<li>Para eliminar el usuario, rellene el
formulario que le presentamos a continuación:</li>
</ul>
<h2>Eliminar usuario</h2>
<form action="eliminar.jsp" method="post"
name="form2" id="name="form2">
<label for="nifacc">NIF*:
<input id="nifacc" name="nifacc" />
</label>
<input type="submit"
value="Eliminar usuario"
id="eliminaracc"
name="eliminaracc" />
</form>
</noscript>
Lisa les propone mostrar la página a varios compañeros, desactivándoles el javascript, para ver si les queda clara la forma de interactuar con el formulario. Estos compañeros ven la página así:
Pronto se dan cuenta de que puede que la página sea accesible, pero no resulta demasiado usable, parece que los usuarios son reacios a leer instrucciones. Después de intentar reiteradamente interactuar con los primeros botones y maldecir porque no funcionan, algunos se deciden a leer el texto explicativo. En el mejor de los casos han perdido mucho tiempo, en el peor se han rendido.
Por otro lado, una vez superada la euforia inicial, Pedro y Hugo empiezan a reflexionar sobre el sobreesfuerzo de programación y el aumento del peso de la página, esta solución empieza a ser poco práctica para implementar y mantener en todos los formularios de la aplicación, bastante más complejos que este.
La última razón para desechar esta opción se la proporciona Lisa: ups! se le olvidó comentar que la etiqueta "noscript" ya no es bien vista por el W3C y no estará en el estándar XHTML2.0
¿Y si utilizamos las etiquetas <a>
o <button>
?
Clasificación:NO accesible/NO nos sirve
A estas alturas se ha extendido el rumor y es la comidilla de la oficina que Hugo, Pedro y Lisa no son capaces de crear un simple formulario compuesto de un campo y tres botones. Así que Gabi, a quien le atraen los marrones más que a una mosca, se deja caer por ahí.
"Si no podéis usar botones, ¿por qué no usáis etiquetas <a>
que con el estilo simulen un botón? Mejor aún, ¿por qué no utilizáis <button>?"
<button>
es una de esas etiquetas que apenas se usan, hasta tal punto que llegamos a dudar de que sea estándar. Pero lo es, incluso en la especificación XHTML 1.1.
Un <button>
puede contener una etiqueta <a>
, por tanto PARECE que es una ventaja utilizar <button>
en vez de utilizar <a>
: ya que tendrá aspecto de botón y se hundirá al pulsarlo sin necesidad de simularlo con estilos, además es un elemento de formulario y por ello PARECE más apropiado.
Y digo PARECE porque <button>
en realidad no se utiliza debido a que no funciona correctamente en Explorer.
Pedro y Hugo tienen otras razones para no usar la alternativa de Gabi, bien con enlaces bien con botones "nos sirve para el botón 'Cancelar' porque sólo navega, pero con el resto de botones queremos someter la página, así que necesitaríamos añadir al enlace, al botón o al enlace dentro del botón un evento javascript que enviara el formulario, y si hacemos el botón de tipo 'submit' estaríamos también igual que antes".
Otro callejón sin salida.
XForm
Clasificación:NO accesible/NO nos sirve
A estas alturas, Hugo, Pedro, Lisa y Gabi deciden que necesitan a Feder, el friki de la empresa, así que se dirigen en procesión a su mesa.
"XForm, esto se soluciona con XForm". Sus compañeros le miran con devoción, no tienen ni idea de lo que les habla, pero por lo visto están salvados.
XForm,- les explica Feder-, es recomendación oficial del W3C desde marzo de 2006, es la nueva generación de formularios que nos permite separar la presentación del contenido.
[en el modelo de datos] <model> [...] <submission action="nuevo.jsp" method="post" id="crear"/> <submission action="eliminar.jsp" method="post" id="eliminar"/> <submission action="principal.jsp" method="post" id="cancelar"/> [...] [en el body] [...] <submit submission="crear"> <label>Crear usuario</label> </submit> <submit submission="eliminar"> <label>Eliminar usuario</label> </submit> <submit submission="cancelar"> <label>Cancelar</label> </submit>
Feder les indica dónde pueden ver un ejemplo.
Al cabo de un rato regresan a la mesa de Feder: hemos probado con Firefox, con Explorer... pero no conseguimos que funcione.
Bueno, es que actualmente ningún navegador soporta XForm nativamente,- les explica,- pero existen plugins y extensiones para Explorer y Firefox.
Sus compañeros le hacen ver que no pueden obligar al usuario a utilizar determinado navegador y además instalarse un plugin o extensión.
Bueno,- insiste Feder- también se pueden convertir en el servidor, en tiempo de ejecución, a formularios de HTML, hay proyectos de código abierto.
También podéis echar un vistazo a AJAXForms,- añade Feder- que transforma documentos XHTML/XForms en páginas HTML con javascript, cuya comunicación con el servidor se restringe al intercambio de datos utilizando técnicas AJAX.
Sus compañeros se deshinchan... si transformamos los documentos XHTML/XForms en páginas HTML con javascript... ¿qué hemos ganado? Estamos otra vez en el punto de partida.
MVC
Clasificación:Accesible y recomendable ¡bingo! ¡usémoslo!
Hugo les da las gracias a todos y decide enviar un mensaje a la lista de correo de la empresa pidiendo más ideas. No tarda en llegar la respuesta.
<form action="./UsuariosServlet"
name="form1"
id="form1"
method="post">
[...]
<input type="hidden"
value="Usuario"
id="pageOperation"
name="pageOperation" />
<input type="submit"
value="Crear usuario"
id="evento_nuevo"
name="evento_nuevo" />
<input type="submit"
value="Eliminar usuario"
id="evento_eliminar"
name="evento_eliminar" />
<input type="submit"
value="Cancelar"
id="evento_cancelar"
name="evento_cancelar" />
</form>
Limpio, transparente, fácil de mantener, 100% accesible... Dejemos que la aplicación, en el servidor, en función del valor del "pageOperation"
y del botón pulsado (fácil de identificar porque su "name"
comienza con "evento") decida qué acción realizar.
Importante:
- No utilizar
<button type="submit" ...
en vez de<input type="submit" ...
puesto que<button>
funciona mal en Explorer y enviará todos los botones y por tanto no podremos saber en el servidor cuál se ha pulsado. - Si la página tienen validaciones javascript en función de las cuales se hace o no el "submit" (por ejemplo mediante un evento asociado al "onsubmit" del "form") siempre hay que realizar también estas validaciones en el servidor, puesto que al tener botones "submit", si el usuario no tiene javascript activo o su "user-agent" no lo soporta, el formulario se enviará porque se ignorará la validación javascript. Me parece muy interesante la reflexión que hace b-Make acerca de las páginas que contienen una cláusula legal que hay que aceptar para enviar el formulario.
NOTA: Toda la historieta de fondo es inventada con personajes ficticios, así me ha parecido más amena.
Artículos relacionados:
- Detectar si una imagen se ha cargado. Descripción extensa de una imagen: accesible con lector de pantalla y visible sin imágenes activas
- Qué teclas de acceso rápido (accesskey) utilizar
- AJAX accesible
- Enlaces que actúan como botones. Implementación accesible.
- Asociación compleja de radios y labels de forma accesible
- Formularios usables: 60 Directrices de Usabilidad
Buenas Olga, me ha encantado el artículo. Una forma muy didáctica de acercarnos a la forma correcta de hacer las cosas...
No has comentado, y creo que tendrías que haber remarcado con mayusculas, que haciendo las cosas bien (caso MVC) te ahora líneas de código, tiempo y problemas.
Saludos.
Eliminar comentario de ' Unknown ' con fecha de 25 de julio de 2007, 8:20
muy didáctico. te has ganado un lector =)
Eliminar comentario de ' Anónimo ' con fecha de 27 de julio de 2007, 17:57
Me voy de vacaciones.
Nos vemos a final de Agosto.
Eliminar comentario de ' Olga Carreras ' con fecha de 27 de julio de 2007, 18:46
Genial artículo Olga, te doy la enhorabuena.
Eliminar comentario de ' Álvaro ' con fecha de 30 de julio de 2007, 9:15
Muy buena olga, pero a mi me surge una duda, tengo un formulario con varios campos de texto y varios botones y quiero que cuando pulse enter se me seleccione el boton de al lado del texto en el que he escrito, es decir, cambiar el boton de envío por defecto, ya que alguno de mis botones tienen asociada una funcion, entonces no es solo por el envio de datos
Un saludo, Ignacio
Eliminar comentario de ' Anónimo ' con fecha de 6 de agosto de 2007, 9:29
Perfecto. Yo tenía el mismo problema y de verdad he ido pasando por esas fases más o menos en el mismo orden XD
Desde luego que con la historia que te has marcado se entiene mucho mejor
Eliminar comentario de ' Mol ' con fecha de 23 de mayo de 2008, 14:01
Hola, me gustaria saber si hay algun ejemplo para gestionar por parte del servidor que boton se pulsa del formulario.
Si pudieras indicarme alguna pagina con un ejemplo o algo sencillo por tu parte.
Un saludo y buen articulo
Eliminar comentario de ' Hector ' con fecha de 25 de agosto de 2008, 11:14
hola!
He estado buscando como mas no poder este cuento de tener varios botones en un formulario con jsp.
Ahora lo encuentro pero no lo entiendo, he intentado de todo!
Por eso te pido el favor de que hagas un ejemplo.
Gracias...
Eliminar comentario de ' Anónimo ' con fecha de 29 de octubre de 2008, 4:43
Yo trabajo con .net, y la verdad el codigo cambia bastante, aunque con los nuevos frameworks de JS toca volver a las bases del HTML y el JS, entendi bien la diferencia con tu articulo, muchas gracias..
Eliminar comentario de ' Anónimo ' con fecha de 11 de marzo de 2009, 19:36
me ha encantado, muy buena didáctica, estoy empezando a aplicar la accesibilidad y usabilidad en j2ee y me vienen muy bien estos ejemplos.
Eliminar comentario de ' Elena ' con fecha de 29 de julio de 2009, 16:34
Magnifico documento, una manera amena y didactica de presentar parejas de problema/solucion, te felicito por ello.
Jose
Eliminar comentario de ' Anónimo ' con fecha de 10 de noviembre de 2009, 15:19
Hola, grax por la info pero tengo unas dudas. Tambien te pediría que agregues un ejemplo.
Por qué el action="./Usuarios" ??
Cómo sabemos qué botón se presionó??
Eliminar comentario de ' zeus13 ' con fecha de 22 de mayo de 2010, 6:54
Típico, creas una buena historia pero dejas un final inconcluso
Eliminar comentario de ' Anónimo ' con fecha de 20 de septiembre de 2010, 18:53
Para los últimos dos comentarios repito:
dejamos que la aplicación, en el servidor, en función del valor del "pageOperation" y del botón pulsado (fácil de identificar porque su "name" comienza con "evento") decida qué acción realizar.
Eliminar comentario de ' Olga Carreras ' con fecha de 20 de septiembre de 2010, 20:56
Muy buen articulo... a mi me ha servido mucho.
Gracias.
Eliminar comentario de ' cazaplanetas ' con fecha de 28 de diciembre de 2010, 7:38
hola olga!! muy buen articulo, te dire que soy muy nuevo en esto y tal vez te resulte muy boba mi pegunta jeje.. ¿podrias explicarme como me entero que boton pulse en mi aplicacion .php? ya se que aqui mencionas que con el "name" pero ¿podrias darme un pequeño ejemplo?
saludos!
muchas gracias por tu tiempo!!! :)
Eliminar comentario de ' Anónimo ' con fecha de 23 de agosto de 2011, 8:14
Hola, yo tengo una duda, como puedo hacer que un solo formulario entregue datos a varios sistemas, ejemplo, rellenas el formulario y envia datos a ingreso de pagina, formato de afiliado, newsletter.
Podrias ayudarme?
anjimgo@gmail.com
Eliminar comentario de ' Planit ' con fecha de 26 de septiembre de 2011, 21:39
El ejemplo que ponía era con JSP, por eso Zeus13 pongo en el action "./Usuarios", es la llamada al servlet a ejecutar.
Para los que preguntan que cómo se programa la deteccción del botón pulsado, eso ya depende del lenguaje de programación que uses.
Siguiendo el ejemplo del servlet, lo más básico sería:
public class ServletAccesible extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doAccesible(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doAccesible(req, resp);
}
void doAccesible(HttpServletRequest req, HttpServletResponse resp) {
if (req.getParameter("aceptar")!=null) {
}
else if (req.getParameter("cancelar")!=null) {
}
}
}
A partir de ahí tendrías que trabajarlo para que fuera reaprovechable para toda la aplicación.
Eliminar comentario de ' Olga Carreras ' con fecha de 3 de noviembre de 2011, 22:18
Hola, no me quedo claro si la operacion (nuevo, eliminar, cancelar) se guarda en el input hidden pageOperation. Si es asi ¿como se actualiza ese valor dependiendo de que boton se pulse? Si no es asi ¿que valor se guarda ahi?
saludos!
Eliminar comentario de ' Anónimo ' con fecha de 20 de marzo de 2012, 13:46
buen ejemplo
Eliminar comentario de ' Anónimo ' con fecha de 23 de julio de 2012, 18:11
buen ejemplo
Eliminar comentario de ' equicom ' con fecha de 4 de septiembre de 2012, 22:27
Sencillo y práctico.
Una forma de utilzarlo si desde el action del form llamamos a un PHP podría ser la siguiente:
$sBotonPulsado = '';
foreach ($_POST as $sPostInd => $postval) {
if (preg_match('/^evento_/', $sPostInd)) {
$sBotonPulsado = preg_replace('/^evento_/', '', $sPostInd);
}
}
if ($sBotonPulsado != '') {
// ...
}
Eliminar comentario de ' Anónimo ' con fecha de 18 de septiembre de 2012, 14:32
weon enredao...bastaba con poner "esto es mejor que esto por tal motivo y listo"....
Eliminar comentario de ' Anónimo ' con fecha de 22 de noviembre de 2012, 17:01
lo maximo seria bueno si tb explicaras como unir animaciones javafx en id netbeans para java web y softwares externos con los famosos metodos primitivos..
Saludos!
Eliminar comentario de ' Anónimo ' con fecha de 8 de marzo de 2013, 5:34
Muchísimas gracias!
Eliminar comentario de ' Anónimo ' con fecha de 2 de noviembre de 2014, 21:24
Muchas Gracias, me sirvió de ayuda.., muy buena exposición
Eliminar comentario de ' Unknown ' con fecha de 10 de diciembre de 2015, 19:00
PERO QUIEN COÑO ES HUGOOOOO!?!??!?!!?!?!?!?!??!?!!?
Eliminar comentario de ' Anónimo ' con fecha de 12 de octubre de 2016, 18:59
Buenas gran contenido lo estuve tratando de probar pero tengo una duda ¿el donde se sitúa? porque la referencia "Feder les indica dónde pueden ver un ejemplo" esta caída. Desde ya muchas gracias
Eliminar comentario de ' Unknown ' con fecha de 10 de febrero de 2018, 14:20
Olga muy didáctico este tutorial si puedieras ayudarme en esto: tengo un formulario que al ingresarle un número de una imagen me la muestra en una pestaña nueva el asunto es que desearía ponerle dos radio button para que un radio button me extraiga una imagen de una carpeta (men) y el otro la extraiga de otra (lady) saludos y éxitos.
Eliminar comentario de ' Unknown ' con fecha de 15 de febrero de 2018, 16:27
Olga por favor comparte tu codigo :)
Eliminar comentario de ' Unknown ' con fecha de 13 de junio de 2018, 11:01
Hola olga, tengo un problema porque no se como hacer una paginappara que se guarden los usuarios creados, los que he visto son con base de datos, no se puede hacer con otro archivo?, Si sabes podrías ayudarme?
Eliminar comentario de ' Unknown ' con fecha de 16 de septiembre de 2018, 16:38
Genial, gracias
Eliminar comentario de ' Raúl ' con fecha de 9 de marzo de 2019, 14:45
Pinche perdida de tiempo, para que hacerlo tan largo
Eliminar comentario de ' Anónimo ' con fecha de 26 de marzo de 2019, 3:41
Uff muchas gracias, me identifiqué con las historias jajajajaja yo lo estoy programando en PHP y me atoré en como obtener el resultado pero gracias a las respyes de Anomino del 18 de septiembre de 2012, 14:32.
¡Muchas gracias!
Eliminar comentario de ' Unknown ' con fecha de 22 de octubre de 2021, 22:24