Home > other >  Changing a specific input color from within an each loop of inputs in a event
Changing a specific input color from within an each loop of inputs in a event

Time:07-12

I am new to Svelte. I have 2 arrays of letters. One of which is the question and one is the answer. The question has empty values so they can be guessed. The question is displayed through an loop of inputs.

I loop through the inputs, disabling ones that already contain a correct value or ones with spaces. When I enter a correct value in one of the inputs I would like only that input to change the background colour to green. The same goes for an incorrect value changing to red. If it's cleared it changes back to white. A handleInput() function handles this.

Currently, if I enter one correct value all the inputs change green or red. Is there a way to manipulate this so that only the individual id that is targeted changes to the correct colour?

<script>
    let scrambledMessage =["h","","","",""," ","t","o","d","","y"]
    let answer = ["h","e","l","l","o"," ","t","o","d","a","y"];
    
    const colorCode = { white: 'bg-white', red: 'bg-red-500', green: 'bg-green-500' };

    $: color = colorCode.white;
    
    const handleInput = (event) => {
        let val = event.data;
        let id = event.target.id;
        //check to see if val is in answer
        if (val === answer[id]) {
            console.log('You are correct');
            color = colorCode.green;
            //event.target.classList.add(colorCode.green);
        } else if (val === '') {
            color = colorCode.white;
             //event.target.classList.add(colorCode.white);
        } else {
            console.log('You are not correct');
            color = colorCode.red;
            //event.target.classList.add(colorCode.red);
        }
    };
</script>
<svelte:head><link src="https://cdn.tailwindcss.com"></svelte:head>
<div >
    {#each scrambledMessage as mes, i}
        {#if mes === ' '}
            <input
                
                disabled />
        {:else if mes === ''}
            <input
                
                placeholder={mes}
                id={i}
                on:input={(event) => handleInput(event)}
                maxlength="1"
                value={mes} />
        {:else}
            <input
                
                value={mes}
                disabled />
        {/if}
    {/each}
    </div>

Check it out on repl

CodePudding user response:

I would not recommend manipulating DOM like that. This is not how Svelte is intended to be used and subsequent updates can mess with this.

Instead it would be better to have a function that simply returns the intended for the given input. That way the result can be different for each input in the loop.

E.g.

<script>
    const answer = 'hello today'.split('');
    const givenCharacters = 'h____ tod_y';
    const inputs = answer.map(() => '');

    function getColorClass(correctValue, value) {
        if (value === '')
            return 'white';
        
        return correctValue === value ? 'green' : 'red';
    };
</script>
<div>
    {#each answer as answerCharacter, i}
        {#if givenCharacters[i] == answerCharacter}
            <input
                disabled class:grey={answerCharacter == ' '}
                value={answerCharacter} />
        {:else}
            <input
                
                maxlength="1"
                bind:value={inputs[i]} />
        {/if}
    {/each}
</div>

REPL

Here all entered values are stored in an inputs array. It is important that getColorClass is called with inputs[i] since changes to that cause the function to re-evaluate.

There is no need to have two separate inputs just to grey out spaces, that can also be done conditionally via a class:... directive or adding to the class attribute.

  • Related