Search code examples
blazor

Blazor conditionally open/close tags not supported?


I want to show portions of my Blazor server page within another content under some condition:

@if (DoOpenTag) {
    <ContainerTag>
}
<MyControl />
@if (DoOpenTag) {
    </ContainerTag>
}

Compiler seems to get completely lost here... I know I could do this:

@if (DoOpenTag) {
    <ContainerTag>
        <MyControl />        
    </ContainerTag>
}
else {
    <MyControl />
}

But the content has quite some code and this leads to code duplication which I'd rather avoid!

Is there any way to achieve what I want here?


Solution

  • Your first code block isn't allowed in Razor markup.

    You can define your inner code block in a Renderfragment and then use it in the conditional statement.

    Here's a simple example to show you how to do it.

    @page "/"
    
    <PageTitle>Index</PageTitle>
    
    <div class="m-2 text-end">
        <button class="btn btn-primary" @onclick=SetShowBox>Toggle Box</button>
    </div>
    
    @if (showBox)
    {
        <div class="bg-dark text-white p-2 m-2">
            @InnerContent
        </div>
    }
    else
    {
        @InnerContent
    }
    
    @code {
        private bool showBox = false;
    
        private void SetShowBox()
            => showBox = !showBox;
    
        private RenderFragment InnerContent => __builder =>
        {
            // This can be any Razor Markup block
            <h1>Hello World</h1>
            <div>Welcome to my Blazor Application</div>
        };
    }
    

    Why does your first block cause an error?

    Razor files are compiled into normal C# files by the Razor compiler. The Razor compiler doesn't allow "misformed" markup in code blocks. Your code could easily have a typo or logic that added the wrong closing tag.

    Here's what gets emitted for the main block:

    if (showBox)
    {
        __builder.OpenElement(10, "div");
        __builder.AddAttribute(11, "class", "bg-dark text-white p-2 m-2");
        __builder.AddContent(12, InnerContent);
        __builder.CloseElement();
    }
    else
    {
        __builder.AddContent(13, InnerContent);
    }