Cómo pasar parámetros a on: haga clic en Svelte?

24

Enlazar una función a un botón es fácil y directo:

<button on:click={handleClick}>
    Clicks are handled by the handleClick function!
</button>

Pero no veo una manera de pasar parámetros (argumentos) a la función, cuando hago esto:

<button on:click={handleClick("parameter1")}>
    Oh no!
</button>

La función se llama al cargar la página y nunca más.

¿Es posible pasar parámetros a la función desde la que se llama on:click{}?


EDITAR:

Acabo de encontrar una manera hacky de hacerlo. Llamar a la función desde un controlador en línea funciona.

<button on:click={() => handleClick("parameter1")}>
    It works...
</button>
FelDev
fuente
Eso es lo que incluso los documentos no han mencionado explícitamente. Pero sí, esa es la forma por ahora, creo ... Hasta que encuentren una solución diferente ...
Manish
66
Esto no es un truco, es cómo funciona . Se menciona explícitamente en el tutorial svelte.dev/tutorial/inline-handlers
Rich Harris
3
¡Gracias por tus comentarios! Esta "forma hacky" de hacerlo no es tan mala después de todo, pero me atrevería a decir que los documentos y el tutorial no son muy explícitos al respecto. Quizás sea solo yo, sin embargo.
FelDev

Respuestas:

5

TL; DR

Simplemente ajuste la función del controlador en otra función, por elegancia use la función de flecha


Debe usar una declaración de función y luego llamar al controlador con argumentos. La función de flecha es elegante y buena para este escenario.

¿POR QUÉ necesito otro contenedor de funciones?

Si usara solo el controlador y pasara los parámetros, ¿cómo se vería?

Probablemente algo como esto:

<button on:click={handleClick("arg1")}>My awesome button</button>

Pero recuerda, handleClick("arg1")así es como invocas la función al instante, y eso es exactamente lo que está sucediendo cuando la pones de esta manera, se llamará cuando la ejecución llegue a esta línea, y no como se esperaba, HAGA CLIC EN EL BOTÓN ...

Por lo tanto, necesita una declaración de función, que será invocada solo por el evento click y dentro de ella llamará a su controlador con todos los argumentos que desee.

<button on:click={() => handleClick("arg1", "arg2")}>
    My awesome button
</button>

Como @Rich Harris (el autor de Svelte) señaló en los comentarios anteriores: Esto no es un truco, pero es lo que la documentación muestra también en sus tutoriales: https://svelte.dev/tutorial/inline-handlers

V. Sambor
fuente
12

Rich ha respondido esto en un comentario, así que acéptalo, pero la forma de vincular los parámetros en un controlador de clics es la siguiente:

<a href="#" on:click|preventDefault={() => onDelete(projectId)}>delete</a>

function onDelete (id) {
  ...
}

Para proporcionar algunos detalles adicionales a las personas que también luchan con esto, y debería estar en los documentos si no lo está, también puede obtener el evento click en dicho controlador:

<a href="#" on:click={event => onDelete(event)}>delete</a>

function onDelete (event) {
  // if it's a custom event you can get the properties passed to it:
  const customEventData = event.detail

  // if you want the element, you guessed it:
  const targetElement = event.target
  ...
}
Antony Jones
fuente
¿Por qué estás usando enlaces para botones, cuando no tienen URL?
mikemaccana
Debido a que construyo PWA que tienen enlaces como retrocesos, es más una razón de hábito. Podría ser fácilmente un botón.
Antony Jones
1

Lo tengo trabajando con esto:

<a href="#" on:click|preventDefault={onDelete.bind(this, project_id)}>delete</a>

function onDelete(id) {
}
chovy
fuente
1

Aquí está con un método de rebote y argumento de evento:

<input type="text" on:keydown={event => onKeyDown(event)} />


const onKeyDown = debounce(handleInput, 250);

async function handleInput(event){
    console.log(event);
}
chovy
fuente
-1

No hay una forma clara mencionada en la documentación y su solución funcionará, pero de hecho no es muy elegante. Mi propia solución preferida es usar curry en el bloque de script .

const handleClick = (parameter) => () => {
   // actual function
} 

Y en el HTML

<button on:click={handleClick('parameter1')>
   It works...
</button>

Cuidado con el curry

Como se menciona en los comentarios, el curry tiene sus trampas. El más común que en el ejemplo anterior handleClick('parameter1')no se activará al hacer clic, sino al renderizar, devolviendo una función que a su vez se activará al hacer clic. Esto significa que esta función siempre usará 'parámetro1' como argumento.

Por lo tanto, usar este método solo sería seguro si el parámetro utilizado es una constante de algún tipo y no cambiará una vez que se procese.

Esto me llevaría a otro punto:

1) Si es una constante que usa un parámetro, también podría usar una función separada

const handleParameter1Click = () => handleClick('parameter1');

2) Si el valor es dinámico pero está disponible dentro del componente, esto aún podría manejarse con una función independiente:

let parameter1;
const handleParameter1Click = () => handleClick(parameter1);

3) Si el valor es dinámico pero no está disponible desde el componente porque depende de algún tipo de alcance (por ejemplo: una lista de elementos representados en un bloque # cada) enfoque 'hacky' funcionará mejor. Sin embargo, creo que sería mejor en ese caso tener los elementos de la lista como un componente y recurrir al caso # 2

Para concluir: el curry funcionará bajo ciertas circunstancias, pero no se recomienda a menos que sea muy consciente y cuidadoso sobre cómo usarlo.

Stephane Vanraes
fuente
3
¡No hagas esto! Simplemente cree una función en línea ( on:click={() => handleClick('parameter1')})
Rich Harris
1
Me acabo de dar cuenta de que esa es la propuesta a la que estabas respondiendo. La razón por la que desaconsejo el enfoque de curry es doble: en primer lugar, es menos claro de inmediato lo que está sucediendo (las personas tienden a suponer que eso handleClick('parameter1')es lo que sucede cuando ocurre el clic , incorrectamente. En segundo lugar, significa que el controlador debe recuperarse cada vez que cambian los parámetros, que es subóptimo. Actualmente, hay un error, lo que significa que de todos modos no funciona svelte.dev/repl/a6c78d8de3e2461c9a44cf15b37b4dda?version=3.12.1
Rich Harris
1
Es cierto que no sabía que ese error nunca lo había encontrado. Por otra parte, en la base de código en la que estoy trabajando, nunca pasamos parámetros como este, casi siempre son objetos y parece funcionar: svelte.dev/repl/72dbe1ebd8874cf8acab86779455fa17?version=3.12.1
Stephane Vanraes
Actualicé mi respuesta con algunas trampas y otras reflexiones. Gracias por el aporte
Stephane Vanraes
Ah, sí, funcionará con objetos, siempre que la referencia en sí no cambie (y el error subyacente también se solucionará a su debido tiempo)
Rich Harris