Home > OS >  Svelte click handler toggle boolean in array from div
Svelte click handler toggle boolean in array from div

Time:11-05

The toggle works only if clicking on a button, ignores the div, seems button triggers some sort of state change, how do I get this to work when clicking anywhere ?

ToolBar.ts

export default class ToolBar  {
    options:Array<ToolBarOptions>;
    constructor() {
        this.options = [
            new ToolBarOptions(ToolButton.sideMenu,SideMenuIcon,false,true, []),
            new ToolBarOptions(ToolButton.mainMenu,MainMenuIcon,false,true, [ new ToolBarOptions(ToolButton.export,exportIcon,true,true,[])]),
            new ToolBarOptions(ToolButton.entities,EntityIcon,false,true,[]),
            new ToolBarOptions(ToolButton.setting,settingsIcon,false,true,[]),
        ];
    }
}

class ToolBarOptions  {
    disabled:boolean;
    name:ToolButton;
    icon:string;
    show:boolean;
    options:Array<ToolBarOptions>;
    constructor(name: ToolButton,icon:string,disabled:boolean,show:boolean, options:Array<ToolBarOptions>) {
        this.name = name;
        this.disabled = disabled;
        this.icon = icon;
        this.show=show;
        this.options=options;
    }
}

export const enum ToolButton{
    mainMenu="mainMenu",
    export="export",

    entities="entities",
    sideMenu="sideMenu",
    setting="setting",
}

App.svelte

let toolbarOptions = new ToolBar();


function handleClickOutSide() {
console.log(toolbarOptions.options)
toolbarOptions.options.forEach((o) => {
o.show=!o.show;
});

console.log(toolbarOptions.options)
    <div  on:click={handleClickOutSide } >
  <ul >
    {#each toolbarOptions.options as  {name,  icon,options, show }, i}
    <li>
      
      <button on:click={()=>show=!show} name={name} h-10":""}">
        {#if toolbarOptions.options.length-1 ===i}
        <div>100%</div>
        {/if}

        <icon>  {@html icon}</icon>
        <span>
          <svg fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" >
            <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
          </svg>
        </span>

        {#if  options.length >0 }

        <div hidden":""}">
          <ul >
            {#each options as  {name,  icon,show }}
            <li >
                <span >  {@html icon}  </span>
                <span > {name}</span>
            </li>
            {/each}
          </ul>
        </div>
        {/if}

      </button>
    
    </li>
    {/each}
  </ul>
</div>

CodePudding user response:

When interacting with each item in a list there are several options that take reactivity into account:

  • Use item index access
  • Map all items
  • Use a dummy assignment

Examples for each:

let items = [
    { name: 'Item 1', checked: false },
    { name: 'Item 2', checked: false },
    { name: 'Item 3', checked: false },
];

const toggleViaIndex = () =>
    items.forEach((e, i) => items[i].checked = !items[i].checked);

const toggleViaMap = () =>
    items = items.map(item => ({ ...item, checked: !item.checked }));

const toggleViaDummyAssignment = () => {
    items.forEach(item => item.checked = !item.checked);
    items = items;
}

REPL

Personally, I am not a fan of the dummy assignment, because it looks like a useless statement. You can of course add comments to make it clearer why the statement exists.


I would not recommend using classes unless necessary, by the way. It breaks things like the map approach, if the class defines any functions or the prototype matters, because those aspects get lost in the spread.

Also: click events on things that are not button elements should always have a keyboard equivalent for accessibility; in this case probably an escape press.

You also probably should just set show to false rather than invert it on click outside.


By the way, ToolBarOptions could be shortened significantly via TypeScript:

class ToolBarOptions {
    constructor(
        public name: ToolButton,
        public icon: string,
        public disabled: boolean,
        public show: boolean,
        public options: Array<ToolBarOptions>,
    ) { }
}
  • Related