Como passar parâmetros para on: clique em Svelte?

24

A ligação de uma função a um botão é fácil e direta:

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

Mas não vejo uma maneira de passar parâmetros (argumentos) para a função, quando faço isso:

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

A função é chamada no carregamento da página e nunca mais.

É possível passar parâmetros para a função chamada from on:click{}?


EDITAR:

Acabei de encontrar uma maneira hacky de fazer isso. Chamar a função de um manipulador embutido funciona.

<button on:click={() => handleClick("parameter1")}>
    It works...
</button>
FelDev
fonte
Isso é o que nem os documentos mencionaram explicitamente. Mas sim eis o caminho para agora eu acho .. Até que venha com uma solução diferente ..
Manish
6
Isso não é um truque, é assim que funciona . É explicitamente mencionado no tutorial svelte.dev/tutorial/inline-handlers
rico Harris
3
Obrigado por seus comentários! Esse "jeito hacky" de fazer isso não é tão ruim, afinal, mas eu ousaria dizer que os documentos e o tutorial não são muito explícitos sobre isso. Talvez seja só eu, no entanto.
FelDev

Respostas:

5

TL; DR

Basta envolver a função de manipulador em outra função, para elegibilidade, use a função de seta


Você precisa usar uma declaração de função e chamar o manipulador com argumentos. As funções de seta são elegantes e boas para esse cenário.

POR QUE preciso de outro wrapper de função?

Se você usasse apenas o manipulador e passasse os parâmetros, como seria?

Provavelmente algo como isto:

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

Mas lembre-se, handleClick("arg1")é assim que você invoca a função instantaneamente, e é exatamente isso que está acontecendo quando você a coloca dessa maneira; ela será chamada quando a execução atingir essa linha, e não como o esperado, NO BOTÃO CLIQUE ...

Portanto, você precisa de uma declaração de função, que será invocada apenas pelo evento click e, dentro dele, chamará o manipulador com os argumentos que desejar.

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

Como @Rich Harris (o autor do Svelte) apontou nos comentários acima: Isso não é um hack, mas é o que a documentação mostra também em seus tutoriais: https://svelte.dev/tutorial/inline-handlers

V. Sambor
fonte
12

Rich respondeu a isso em um comentário, portanto, agradeça a ele, mas a maneira de vincular parâmetros em um manipulador de cliques é a seguinte:

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

function onDelete (id) {
  ...
}

Para fornecer alguns detalhes extras para as pessoas que também enfrentam isso, e isso deve constar nos documentos, caso contrário, você também pode obter o evento click em um manipulador:

<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
fonte
Por que você está usando links para botões, quando eles não têm URL?
Mikemaccana
Como eu construo PWAs que têm links como fallbacks, é mais uma razão de hábito. Poderia facilmente ser um botão.
Antony Jones
1

Eu trabalhei com isso:

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

function onDelete(id) {
}
chovy
fonte
1

Aqui está um método de debounce e um argumento de evento:

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


const onKeyDown = debounce(handleInput, 250);

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

Não há uma maneira clara mencionada na documentação e sua solução funcionará, mas de fato não é muito elegante. Minha própria solução preferida é usar currying no próprio bloco de scripts .

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

E no HTML

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

Cuidado com o curry

Como mencionado nos comentários, o curry tem suas armadilhas. A mais comum que no exemplo acima handleClick('parameter1')não será acionada ao clicar, mas na renderização, retornando uma função que por sua vez será acionada ao clicar. Isso significa que essa função sempre usará 'parameter1' como argumento.

Portanto, o uso desse método só seria seguro se o parâmetro usado for uma constante de algum tipo e não será alterado após a renderização.

Isso me levaria a outro ponto:

1) Se é uma constante usada um parâmetro, você também pode usar uma função separada

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

2) Se o valor for dinâmico, mas disponível no componente, isso ainda poderá ser tratado com uma função autônoma:

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

3) Se o valor for dinâmico, mas não estiver disponível no componente, porque isso depende de algum tipo de escopo (por exemplo: uma lista de itens renderizados em um bloco #each) a abordagem 'hacky' funcionará melhor. No entanto, acho que seria melhor, nesse caso, ter os elementos da lista como um componente e voltar ao caso 2

Para concluir: o curry funcionará sob determinadas circunstâncias, mas não é recomendado, a menos que você esteja muito ciente e cuidadoso sobre como usá-lo.

Stephane Vanraes
fonte
3
Não faça isso! Basta criar uma função embutida ( on:click={() => handleClick('parameter1')})
Rich Harris
11
Acabei de perceber que é a proposta à qual você estava respondendo. O motivo pelo qual desaconselho a abordagem do curry é dupla: primeiro, fica menos claro o que está acontecendo (as pessoas tendem a supor que handleClick('parameter1')é o que acontece quando o clique ocorre incorretamente. Em segundo lugar, isso significa que o manipulador precisa ser recuperado sempre que os parâmetros forem alterados, que é sub-ótima Atualmente, há um erro, o que significa que faz de qualquer maneira não trabalho. svelte.dev/repl/a6c78d8de3e2461c9a44cf15b37b4dda?version=3.12.1
rico Harris
11
É verdade que eu não sabia que esse bug nunca o encontrara. Em seguida, novamente na base de código Eu estou trabalhando em nós nunca passar parâmetro como este, eles são quase sempre os objetos e que parece funcionar: svelte.dev/repl/72dbe1ebd8874cf8acab86779455fa17?version=3.12.1
Stephane Vanraes
Atualizei minha resposta com algumas armadilhas e outras reflexões. Obrigado pela contribuição
Stephane Vanraes
Ah sim, ele vai trabalhar com objetos, enquanto a referência em si não muda (e do bug subjacente vai ficar fixo no devido tempo também)
Rico Harris