Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot have an unclosed HTML element inside an #if block #3913

Closed
calder12 opened this issue Nov 12, 2019 · 8 comments
Closed

Cannot have an unclosed HTML element inside an #if block #3913

calder12 opened this issue Nov 12, 2019 · 8 comments

Comments

@calder12
Copy link

calder12 commented Nov 12, 2019

Describe the bug
You cannot have an unclosed HTML element inside an if block. Meaning you couldn't do conditional div tags in a loop for example

{#each things as thing, index}
  {#if index % 10 === 0}
    <div class="new-div">
  {/if}
  Some other content
  {#if index % 10 === 0}
    </div>
  {/if}
{/each}

That code is a bad example, but it should create a new div every tenth element. Instead it throws an error because the first if block has the unclosed div in it.

This however works fine

{#each things as thing, index}
  {#if index % 10 === 0}
    <div class="new-div"></div>
  {/if}
{/each}
@Almar
Copy link

Almar commented Nov 13, 2019

So maybe this is not a good example but looking at this example I wonder if this is really what you want to do. Personally I like to keep the logic in the template to a minimum; I would divide the things into buckets of things and then in the template have a nested #each (first loop over the buckets, then over the things in the bucket). This approach would also be a workaround for this particular problem.

@calder12
Copy link
Author

Maybe it's just me, but this is a pretty common pattern I think for this type of situation. I could go with your workaround as well @Almar but with the data I have to work with I feel that would be far more complicated and less legible overall.

I still think this is a bug that should probably be considered though, I am sure there are other situations where it might rear its head that I am not thinking of at the moment.

@Conduitry
Copy link
Member

Duplicate of #3133. To quote my comment there:

Supporting that is not something we're interested in doing, though. Svelte needs to know about the structure of the component at compile time. When rendering in the browser, the compiled code is not just concatenating strings together to form the document, it's representing DOM elements in a tree.

@calder12
Copy link
Author

I fail to see how that's a suitable answer to be honest, Svelte I would assume is looking at the entire code and not just parsing it line by line. I don't understand how it can compile an each block into HTML but cannot compile an opening and closing element. Makes me a bit sad, responses like this make me question if Svelte was the right choice.

@randyjensen
Copy link

I understand why Svelte handles this the way it does, but I'll add my use case anyway in case it makes sense to revisit in the future.

I have a list of locations that I iterate through. Some of them have URLs, some don't. In order to make this work, I can duplicate the code in an if/else statement (one with and another without), or I can have the click happen in an on:click.

This is ~how I'd like to write it:

{#each locations as location}
{#if location.url}

{/if}

{#if location.url}

{/if}
{/each}

Instead, I added an on:click and handled all the logic in there. Moving the logic to js in this case also makes styling more difficult. I need to add more logic during the loop to check if a url exists and add the proper cursor to it.

<LocationComponent on:click={() => goToLocation(location)}>

const goToLocation = location => {
if (location.url) {
window.open(location.url);
}
}

I love Svelte because of how favorable it is to writing semantic markup. Having a simple href happen in JS feels to go against the grain of Svelte's vision.

@afreidz
Copy link

afreidz commented Nov 25, 2019

i'd also like to jump on this for the future. my use case is that if an item is "disabled" i would like the entire iteration be wrapped in a span. if the item is NOT disabled, i'd like it to be wrapped in an anchor tag. in my case there is fair amount of additional logic and conditional rendering below that determination. if we could have something like partials, i wouldn't feel so bad about enclosing a complete/closed block inside the {#if} tag. but having to duplicate a larger chunk to make it render conditionally inside an anchor vs span is not very DRY.

@pngwn
Copy link
Member

pngwn commented Nov 25, 2019

You can put the additional logic/ UI in a component:

{#if condition}
  <div>
    <Contents />
  </div>
{:else}
  <a>
    <Contents />
  </a>
{/if}

@kkukshtel
Copy link

I also ran into this issue. My solution isn't great, but basically I needed a contextual <tr> or </tr> to be able to dynamically resize an HTML table based on user input. Before I had tried to wrap the tr statements inside conditionals inside an each loop, but I figure out a way around it was to basically double wrap content block so I could use the outer index as an offset:

    {#each schemaData as s,outerIndex}
        {#if outerIndex % displayWidth === 0}
        <tr>
            {#each schemaData as schema,i}
                {#if i >= outerIndex && i < outerIndex + displayWidth}
                    <td style="width:{columnWidth}px;height:{columnHeight}px">
                        <EnumField  />
                    </td>
                {/if}
            {/each}
        </tr>
        {/if}
    {/each}

It works but it feels kind of gross. Being able to wrap tags somehow would be nice, but this is working for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants