En este recorrido por la creación de formularios interactivos con Svelte, nos hemos centrado en cómo manejar eventos y binding para lograr una experiencia de usuario clara y funcional. Empezamos implementando un campo desplegable para seleccionar el sector laboral, usando un select con binding en su valor para que el estado se sincronice automáticamente con la opción elegida.
Para ello, definimos una lista de sectores como backend, frontend, devops y QA, y configuramos el valor inicial en frontend, aunque no fuera la primera opción en la lista. Esto nos permitió comprobar que el binding funciona correctamente, ya que el valor inicial se refleja en el desplegable sin importar su posición en las opciones.
Luego, creamos un componente personalizado llamado DropDown.svelte que recibe varias propiedades: un identificador para la etiqueta, un label para mostrar el texto descriptivo, una lista de opciones (choices) y un valor (value) que se bindea con el select. En el componente, usamos un label asociado al select y generamos las opciones dinámicamente a partir de la lista recibida, asignando el mismo string como valor y texto visible. El binding con bind:value asegura que cualquier cambio en el select actualice la variable del estado padre y viceversa.
<script>
export let identifier;
export let label;
export let choices = [];
export let value;
</script>
<p>
<label for={identifier}>{label}</label>
<select id={identifier} bind:value={value}>
{#each choices as choice}
<option value={choice}>{choice}</option>
{/each}
</select>
</p>
Al importar y usar este componente, pudimos verificar que el valor inicial se mostraba correctamente y que al cambiar la selección, el estado se actualizaba y se reflejaba en el formulario.
El siguiente paso fue crear un componente más complejo para manejar rangos salariales, llamado Rangos.svelte. Aquí nos alejamos del binding directo y optamos por usar eventos personalizados para manejar la interacción, lo que es útil cuando un componente tiene múltiples valores relacionados que queremos enviar como un solo objeto.
En Rangos.svelte, definimos propiedades para el identificador, la etiqueta, el valor mínimo y máximo permitidos, y usamos la función createEventDispatcher de Svelte para emitir eventos propios. El componente muestra dos controles deslizantes (input tipo range), uno para el valor mínimo y otro para el máximo, cada uno con su propia etiqueta que combina el identificador con un sufijo _min o _max para mantener la accesibilidad y claridad.
<script>
import { createEventDispatcher } from 'svelte';
export let identifier;
export let label;
export let minValue;
export let maxValue;
const dispatch = createEventDispatcher();
let currentMin = minValue;
let currentMax = maxValue;
function cambiarMinimo(e) {
const nuevoMin = parseInt(e.target.value);
currentMin = nuevoMin;
dispatch('update', { min: currentMin, max: currentMax });
}
function cambiarMaximo(e) {
const nuevoMax = parseInt(e.target.value);
currentMax = nuevoMax;
dispatch('update', { min: currentMin, max: currentMax });
}
</script>
<p>
<label for="{identifier}_min">{label} mínimo</label>
<input
id="{identifier}_min"
type="range"
min="0"
max="50000"
value={currentMin}
on:change={cambiarMinimo}
/>
</p>
<p>
<label for="{identifier}_max">{label} máximo</label>
<input
id="{identifier}_max"
type="range"
min="0"
max="50000"
value={currentMax}
on:change={cambiarMaximo}
/>
</p>
Al usar este componente en el formulario principal, escuchamos el evento update para actualizar el estado con los nuevos valores de mínimo y máximo. Esto mantiene sincronizados los valores y permite que el formulario refleje los cambios en tiempo real.
Además, implementamos una validación sencilla para evitar que el valor mínimo sea mayor que el máximo. Para ello, añadimos una propiedad error que, si no es nula, desactiva los inputs y muestra un mensaje de error. Esto evita que el usuario pueda enviar un formulario con datos incoherentes.
{#if error}
<p>{error}</p>
{/if}
<input
type="range"
min="0"
max="50000"
value={currentMin}
on:change={cambiarMinimo}
disabled={error !== null}
/>
<input
type="range"
min="0"
max="50000"
value={currentMax}
on:change={cambiarMaximo}
disabled={error !== null}
/>
En el componente padre, comprobamos la coherencia de los valores y actualizamos el estado de error en consecuencia, lo que a su vez controla la habilitación o deshabilitación de los controles.
Finalmente, al enviar el formulario, podemos ver reflejados todos los valores introducidos, incluyendo el nombre, el sector seleccionado y el rango salarial, gracias a la correcta gestión de binding y eventos personalizados.
Con este enfoque, hemos aprendido a combinar binding directo en campos select con la creación de componentes personalizados que emiten eventos propios para manejar datos más complejos, como rangos numéricos con validación. Esto nos permite construir formularios semánticos, claros y funcionales en Svelte, facilitando la interacción y el mantenimiento del estado de manera organizada.