Comment passer des paramètres à: cliquer dans Svelte?


24

La liaison d'une fonction à un bouton est simple et directe:

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

Mais je ne vois pas de moyen de passer des paramètres (arguments) à la fonction, quand je fais cela:

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

La fonction est appelée au chargement de la page, et plus jamais.

Est-il possible de passer des paramètres à la fonction appelée on:click{}?


ÉDITER:

Je viens de trouver un moyen hacky de le faire. L'appel de la fonction à partir d'un gestionnaire en ligne fonctionne.

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

C'est ce que même les documents n'ont pas explicitement mentionné. Mais oui c'est le chemin pour le moment je pense .. Jusqu'à ce qu'ils trouvent une solution différente ..
Manish

6
Ce n'est pas un hack, c'est comme ça que ça marche . C'est explicitement mentionné dans le tutoriel svelte.dev/tutorial/inline-handlers
Rich Harris

3
Merci pour vos commentaires! Cette "manière hacky" de le faire n'est pas si mauvaise après tout, mais j'oserais dire que les documents et le tutoriel ne sont pas très explicites à ce sujet. Mais c'est peut-être juste moi.
FelDev

Réponses:


5

TL; DR

Enveloppez simplement la fonction de gestionnaire dans une autre fonction, pour l'élégance, utilisez la fonction flèche


Vous devez utiliser une déclaration de fonction, puis appeler le gestionnaire avec des arguments. La fonction flèche est élégante et bonne pour ce scénario.

POURQUOI ai-je besoin d'un autre wrapper de fonction?

Si vous utilisiez uniquement le gestionnaire et transmettiez les paramètres, à quoi ressemblerait-il?

Probablement quelque chose comme ça:

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

Mais rappelez-vous, handleClick("arg1")c'est ainsi que vous appelez la fonction instantanément, et c'est exactement ce qui se passe lorsque vous la mettez de cette façon, elle sera appelée lorsque l'exécution atteindra cette ligne, et pas comme prévu, SUR LE BOUTON CLIC ...

Par conséquent, vous avez besoin d'une déclaration de fonction, qui sera invoquée uniquement par l'événement click et à l'intérieur, vous appelez votre gestionnaire avec autant d'arguments que vous le souhaitez.

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

Comme @Rich Harris (l'auteur de Svelte) l'a souligné dans les commentaires ci-dessus: Ce n'est pas un hack, mais c'est ce que la documentation montre également dans leurs tutoriels: https://svelte.dev/tutorial/inline-handlers


12

Rich a répondu à cela dans un commentaire, donc merci à lui, mais la façon de lier les paramètres dans un gestionnaire de clic est la suivante:

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

function onDelete (id) {
  ...
}

Pour fournir des détails supplémentaires aux personnes qui ont également des difficultés avec cela, et cela devrait être dans les documents s'il ne l'est pas, vous pouvez également obtenir l'événement click dans un tel gestionnaire:

<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
  ...
}

Pourquoi utilisez-vous des liens pour les boutons, alors qu'ils n'ont pas d'URL?
mikemaccana

Parce que je construis des PWA qui ont des liens comme solutions de rechange, c'est donc plus une raison d'habitude. Cela pourrait facilement être un bouton.
Antony Jones

1

Je l'ai fait travailler avec ceci:

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

function onDelete(id) {
}

1

Le voici avec une méthode anti-rebond et un argument d'événement:

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


const onKeyDown = debounce(handleInput, 250);

async function handleInput(event){
    console.log(event);
}

-1

Il n'y a aucun moyen clair mentionné dans la documentation et votre solution fonctionnera mais n'est en effet pas très élégante. Ma propre solution préférée consiste à utiliser le curry dans le bloc de script lui-même.

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

Et dans le HTML

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

Méfiez-vous du curry

Comme mentionné dans les commentaires, le curry a ses pièges. La plus courante qui, dans l'exemple ci-dessus handleClick('parameter1'), ne sera pas déclenchée lors d'un clic, mais plutôt lors du rendu, renvoyant une fonction qui sera déclenchée à son tour. Cela signifie que cette fonction utilisera toujours 'parameter1' comme argument.

Par conséquent, l'utilisation de cette méthode ne serait sûre que si le paramètre utilisé est une constante quelconque et ne changera pas une fois rendu.

Cela m'amènerait à un autre point:

1) Si c'est une constante utilisée un paramètre, vous pouvez aussi bien utiliser une fonction séparée

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

2) Si la valeur est dynamique mais disponible dans le composant, cela pourrait toujours être géré avec une fonction autonome:

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

3) Si la valeur est dynamique mais n'est pas disponible à partir du composant car cela dépend d'une sorte de portée (par exemple: une liste d'éléments rendus dans un bloc #each), l' approche «hacky» fonctionnera mieux. Cependant, je pense qu'il serait préférable dans ce cas d'avoir les éléments de liste en tant que composants eux-mêmes et de revenir au cas # 2

Pour conclure: le curry fonctionnera dans certaines circonstances mais n'est pas recommandé à moins que vous ne soyez très bien informé et prudent sur la façon de l'utiliser.


3
Ne fais pas ça! Créez simplement une fonction inline ( on:click={() => handleClick('parameter1')})
Rich Harris

1
Je viens de réaliser que c'est la proposition à laquelle vous répondiez. La raison pour laquelle je déconseille l'approche du curry est double: premièrement, il est moins immédiatement clair de ce qui se passe (les gens ont tendance à supposer que handleClick('parameter1')c'est ce qui se passe lorsque le clic se produit , de manière incorrecte. Deuxièmement, cela signifie que le gestionnaire doit être rebondi chaque fois que les paramètres changent, qui est sous-optimal. Actuellement, il y a un bogue, ce qui signifie que cela ne fonctionne pas de toute façon svelte.dev/repl/a6c78d8de3e2461c9a44cf15b37b4dda?version=3.12.1
Rich Harris

1
Certes, je n'étais pas au courant que ce bug ne l'avait jamais rencontré moi-même. Là encore, dans la base de code sur laquelle je travaille, nous ne transmettons jamais de paramètre comme celui-ci, ce sont presque toujours des objets et cela semble fonctionner: svelte.dev/repl/72dbe1ebd8874cf8acab86779455fa17?version=3.12.1
Stephane Vanraes

J'ai mis à jour ma réponse avec des écueils curieux et d'autres réflexions. Merci pour la contribution
Stephane Vanraes

Ah oui, cela fonctionnera avec des objets, tant que la référence elle-même ne change pas (et le bug sous-jacent sera corrigé en temps voulu)
Rich Harris
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.