Conditional rendering of a partial HTML element in Svelte

Viewed 180

As an example, suppose I want to create a component for a group of radio buttons:

<!-- App.Svelte --> 
<script>
    import Radio from './Radio.svelte';
</script>

<main>
    <Radio group={"stooges"}
        btns={["Larry", "Curly", "Moe", "Shep", "Joe", "Curley Joe"]}
        checked={"Curly"}
        disabled={["Moe", "Joe"]}
    />
</main>

The following implementation of the radio group component produces correct behavior; Curly is pre-selected; Moe and Joe are grayed:

<!-- Radio.svelte -->
<script>
  export let group;
  export let btns;
  export let checked;
  export let disabled;
</script>

{#each btns as btn, idx}
  {#if btn === checked}
    {#if disabled.includes(btn)}
      <input type="radio" id={btn} value={btn} name={group} 
        checked disabled>
    {:else}
      <input type="radio" id={btn} value={btn} name={group} checked>
    {/if}
  {:else}
    {#if disabled.includes(btn)}
      <input type="radio" id={btn} value={btn} name={group} disabled>
    {:else}
      <input type="radio" id={btn} value={btn} name={group}>
    {/if}
  {/if}
  <label for={btn}>{btn}</label>
{/each}

Here is another implementation of the radio group component that is cleaner, but will not compile:

<!-- Radio.svelte -->
<script>
  export let group;
  export let btns;
  export let checked;
  export let disabled;
</script>

{#each btns as btn, idx}
  <input type="radio" id={btn} value={btn} name={group}
    {#if btn === checked} checked {/if}
    {#if disabled.includes(btn)} disabled {/if} 
  >
  <label for={btn}>{btn}</label>
{/each}

The compiler flags the opening curly brace of the first #if statement with the message Expected } svelte(unexpected-token).

The only reason I can think of for the error in the second implementation is that, unlike the first implementation, which contains a complete input element on each if-else branch, the second implementation contains a part of an input element on each if-else branch. However, the Svelte docs don't warn against that, as far as I can tell.

1 Answers

You cannot use template syntax ({#if}..{:else}..{/if}, {#each}..{/each}, etc.) inside element/component tags.

You can, however, make element/component attributes resolve based on conditionals (which is what you are trying to achieve):

{#each btns as btn, idx}
  <input
    type="radio"
    id={btn}
    value={btn}
    name={group}
    checked={btn === checked}
    disabled={disabled.includes(btn)}
  >
  <label for={btn}>{btn}</label>
{/each}

checked and disabled will be assigned true or false according to the corresponding statement evaluation.

Demo REPL

Related