Mayor usabilidad para subir imágenes y archivos desde el formulario de inscripción

Sergi Rodrígues  
25-07-2020 19:55  
7 minutes read  

Cuando en un formulario web es necesario que el visitante adjunte una imagen normalmente se usa el control estándar HTML que permite al visitante escoger un archivo de su dispositivo (PC, teléfono,...), pero es un control que normalmente no da mucha información.

Lo que hemos hecho en INSCRIPCION.ONLINE es enriquecer la funcionalidad de ese control HTML con una miniatura de la imagen que se pretende subir (si es una imagen) y el nombre y tamaño del archivo. También hemos añadido un botón para cancelar la subida de ese archivo, si ya se ha seleccionado para subir algún archivo. Así como un aviso acerca del excesivo tamaño del archivo si es más pesado que el límite permitido por el servidor.

Mejora visual

Así se ve un ejemplo de ese control insertado en un formulario de inscripción:

Como puede verse, además hemos podido también enriquecer el aspecto de ese botón, con un icono en forma de carpeta, y con los colores del tema visual de la web en cuestión.

Control del peso del archivo en Mb

Pero además, hemos agregado una verificación del peso del archivo en Mb. Has de saber que todos los servidores tienen un límite máximo de archivo para poder ser subido a través de un formulario HTML. Entonces este nuevo botón mejorado solicita al navegador web información sobre el tamaño del archivo que el usuario selecciona de su equipo y lo compara con el tamaño máximo permitido por el servidor.

Esta verificación en tiempo real ahorra mucho tiempo y frustaciones a los usuarios que hasta ahora escogían un archivo demasiado pesado y solamente cuando acababan de rellenar todo el cuestionario y lo enviaban al servidor recibían una denegación del mismo por culpa del tamaño del archivo enviado. Ahora esto sucede en el mismo momento en el que el usuario selecciona el archivo en su equipo!

Información de confirmación

En el momento en el que el usuario ha seleccionado un archivo del servidor ahora se muestra el nombre del archivo y el tamaño del mismo. Con lo cuál tiene una confirmación más obvia de que ha seleccionado el archivo que quería... o no.

Miniatura de la imagen a subir

Posiblemente la mejora que más luce es la miniatura que a partir de ahora se muestra cuando el usuario ha seleccionado un archivo de tipo imagen renderizable por todos cualquier navegador web: jpeg, jpg, png, svg, gif, ico. Es decir, no sirven archivos de Gimp, Inkscape, Photoshop, etc... Ni tan siquiera PDF (o al menos de momento).

Notas técnicas para desarrolladores de frontend

Porqué sé que a veces aterriza por este blog algún otro desarrollador de frontend, voy a compartir lo sencillo que es manejar estos detalles desde con JQuery.

Visualización del botón HTML

Tan solo debes:

  1. esconder el INPUT type="file" con CSS
  2. agregar un botón HTML que al pulsarlo disparará un click sobre el INPUT FILE escondido
  3. en el INPUT FILE agregar un trigger para el evento de cambio de ese control que llamará a una función de javascript cuando el usuario haya escogido un archivo (o un nuevo archivo)
  4. esa función hace la magia: accede a la lista de archivos seleccionados por el usuario para ese control INPUT FILE y obtiene el peso en bytes (que convertimos a un formato legible (Kb, Mb o Gb) y la extensión del archivo
  5. antes de mostrar la información del archivo comprobamos si el peso en bytes supera al permitido por el servidor
  6. si la extensión del archivo es el de una imagen renderizable en un nodo IMG, lo agrega debajo del nombre del archivo y su peso
  7. mostramos el botón CANCELAR que al pulsarlo vaciará el valor del control INPUT FILE y vaciará la información mostrada acerca del archivo, incluyendo la miniatura si la hubiera

El código quedaría algo como esto:

<input type="file" id="myfile" style="display:none;" 
"onchange='js_changed_file();"  />

<a href="#" onclick="$('#myfile').trigger('click');return false;">
   <b class='fa fa-folder fa-lg'></b> Seleccionar archivo
</a>

<p id="display_filename" style="display:none; word-break: break-all;margin:0.3em;padding:0.5em 1em;"></p>

<script>
	function js_changed_file(){
		var file = document.querySelector('#myfile').files[0];
		
		// == check file size
		var file_bytes  = file.size;
		var limit_bytes = 2 * 1024 * 1024;
		if (file_bytes > limit_bytes){
			alert("El archivo "+file.name+" pesa más de "+js_format_bytes(limit_bytes);
			js_reset_file();
			return;
		}
		
		// == display file info
		var info = file.name+' ['+js_format_bytes(file.size)+']'
		$('#display_filename').html(info);
		js_thumb_file(file,'display_filename');
		$('#display_filename').slideDown();		
	}
	
	function js_thumb_file(file,display_on) {
		if (file.type && file.type.match(/(jpg|jpeg|png|gif|svg|ico)/i) == null) {
			$('#'+display_on).append("<a  onclick='js_reset_file();return false;'><b class='fa fa-remove fa-lg'></b> Cancelar</a>");
			return;
		}
		
		// == esta clase nativa de HTML5 hace la magia
		const reader = new FileReader();
		reader.addEventListener('load', (event) => {
		$('#'+display_on).append('<br /><img src="'+event.target.result+'" style="margin-top:1em;max-width:100%;max-height:120px;" />')
		.append("<br /><a class='bt' onclick='js_reset_file();return false;'><b class='fa fa-remove fa-lg' style='color:inherit;'></b> cancelar</a>");
		});
		reader.readAsDataURL(file);
	}	
	
	function js_reset_file(){
		$('#display_filename').html('').hide();
		$('#myfile').val('');
	}
	
	function js_format_bytes(n_bytes){
		if (n_bytes < 1024) 
			return n_bytes+'b';
		else if (n_bytes < 1024*1024) 
			return (n_bytes/1024).toFixed(1)+'Kb';
		else if (n_bytes < 1024*1024*1024) 
			return (n_bytes/(1024*1024)).toFixed(1)+'Mb';
		else 
			return (n_bytes/(1024*1024*1024)).toFixed(1)+'Gb';
	}
</script>

Si trabajas con PHP en el backend tal vez te interese saber que con estas dos funciones podemos obtener de forma muy segura el límite máximo del peso del archivo a subir a partir de las variables de configuración de PHP post_max_size y upload_max_filesize:

function f_php_file_upload_max_size() {

	$max_size = -1;
	
	$post_max_size = f_parse_size(ini_get('post_max_size'));
	if ($post_max_size > 0) 
		$max_size = $post_max_size;

	$upload_max = f_parse_size(ini_get('upload_max_filesize'));
	if ($upload_max > 0 && $upload_max < $max_size) 
		$max_size = $upload_max;

	return $max_size;
}

function f_parse_size($size) {

	// Remove the non-unit characters from the size.
	$unit = preg_replace('/[^bkmgtpezy]/i', '', $size);
	
	// Remove the non-numeric characters from the size.
	$size = preg_replace('/[^0-9\.]/', '', $size); 
	
	if ($unit) {
		// Find the position of the unit in 
		// the ordered string which is the power 
		// of magnitude to multiply a kilobyte by.
		return round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
		
	}else {
		return round($size);
	}
}

Comments 1   Visits 2297  

  Comments


1
jjjjjjjj:
03-10-2021 19:50
lllllllllll

  

Add your comment:

Comment:
Name:
(anti-bots query)

Send

I'M INTERESTED

CONSULT US

We respond before 12h !!

Discuss your need and interest in this platform. Type of events organized, volume of registrations per month / year, etc ...

(anti-bots query)

  Send