skip to Main Content

I am trying to do the most basic thing in Svelte but I keep failing. I want the button element to trigger the visibillity of the ul-element with classname "this-one". I am stuck in the "vanilla js"-approach and can not wrap my head around how to achieve this the svelte-way. Any pointers?

<ul>
    {#each item.children as child (child.id)}
        <li>
            <div>
                <a href={child.route.path}
                   on:click={() => dispatch('click')}>
                    <span>{child.name}</span>
                </a>
                {#if child.children?.length > 0}
                    <button>
                        <i class="chevron-down"></i>
                    </button>
                {/if}
            </div>
            {#if child.children?.length > 0}
                <ul class="this-one">
                    {#each child.children as grandChild}
                        <li>
                            <a href={grandChild.route.path}
                               on:click={() => dispatch('click')}>
                                {grandChild.name}
                            </a>
                        </li>
                    {/each}
                </ul>
            {/if}
        </li>
    {/each}
</ul>

2

Answers


  1. This is how you can do it

    document.querySelector(".chevron-down").addEventListener("click", function() {
       let context = document.querySelector(".this-one");
       context.classList[context.classList.contains("invisible") ? "add" : "remove"]("invisible");
    });
    

    provided that invisible is properly defined, like display: none;

    Login or Signup to reply.
  2. You would have to store the visibility information either on the item object itself or an external object, e.g. a set, map or in an array by index. (You might not want to have it on the item for various data organization reasons.)

    E.g. using a Set1:

    let expanded = new Set();
    function toggle(id) {
        if (expanded.has(id)) {
            expanded.delete(id);
        } else {
            expanded.add(id);
        }
        // trigger reactivity, since object is mutated internally using methods
        expanded = expanded;
    }
    
    <button on:click={() => toggle(child.id)}>
        <i class="chevron-down"></i>
    </button>
    
    ...
    {#if child.children?.length > 0 && expanded.has(child.id)}
        <ul class="this-one">
            ...
    

    REPL

    If the state is directly on the item, it is the most straightforward:

    <button on:click={() => child.expanded = !child.expanded}>
        <i class="chevron-down"></i>
    </button>
    
    ...
    
    {#if child.children?.length > 0 && child.expanded}
        <ul class="this-one">
            ...
    

    REPL


    1 In Svelte 5 you can use the SvelteSet from 'svelte/reactivity', which updates without any dummy assignment. (Such assignments generally do not do anything in Svelte 5.)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search