I want to apply a CSS animation to any given input field, depending on which value was typed into it.
My .svelte file looks something like this:
<script>
let letterPlaceHolder = new Array(50)
async function submit() {
//Make fetch to backend with all input values.
//Backend returns list of which letters are valid and invalid.
}
</script>
{#each Array(50) as input, i}
<input
type="text"
maxlength="1"
bind:this={letterPlaceHolder[i]}
/>
{/each}
<button id="submit" on:click={submit}>Submit</button>
When the submit function is called, I get a return from the backend, telling me which letters are valid and which are invalid. I want to apply a Boop animation to all elements with an invalid letter. See the example of Boop action here: https://svelte.dev/repl/e606c27c864045e5a9700691a7417f99?version=3.48.0
How can I apply a Boop animation to selected input elements, that are triggered by the response of the backed?
I'm guessing that I need to import a svelte component that animates any given DOM element that I feed it, but I'm not sure how to solve this.
The way I would personally solve this is by also having an array holding the validity of each field and a flag indicating whether to show this state or not:
let invalid = Array(50).fill(false);
let showInvalid = false;
Then in your submit function you fill this array and toggle the flag and a timeout that turns this flag off again.
function submit() {
invalid = resultFromBackend;
showInvalid = true;
// show the invalid states for 1 second
setTimeout(() => showInvalid = false, 1000);
}
With these 2 combined you can now add and remove a class on the input field itself:
{#each Array(5) as input, i}
<input
type="text"
maxlength="1"
bind:value={letterPlaceHolder[i]}
class:invalid={invalid[i] && showInvalid}
/>
{/each}
(I also changed here that you bind the value to letterPlaceHolder instead of the entire element, since you do not need the element itself).
The invalid class would then simply add the css animation like usual.
.invalid {
animation: 1s boop forwards running;
}
Thank you.
I ended up using the solution posted by Stephane.
In my quest to figure out how to apply the animation, I found the animate.css library to handle the animation. So I added this to my Index.html file.
<head>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
/>
</head>
In my .svelte file I added this part:
var animate = false
var invalid = Array(50).fill(false);
When looping over the response from the backend I make something like this:
function submit() {
//Fetching result from backend
for (let i = 0; i < response.length; i++) {
if (response[i] === false) {
invalid[i] = true;
}
}
animate = true;
setTimeout(() => (animate = false), 1000);
}
My svelte element now looks like this
{#each Array(50) as input, i}
<input
type="text"
maxlength="1"
bind:this={letterPlaceHolder[i]}
class:animate__animated={animate && invalid[i]}
class:animate__headShake={animate && invalid[i]}
/>
{/each}