NET8 Blazor components and render mode

674 views Asked by At

I'm creating a Blazor component to have a NuGet package of the design. So, I can use it in different projects. I have a Razor called TopNavBar that displays the header of the page.

<div class="top-navbar style-1">
    <div class="container p-0">
        <div class="row align-items-center">
            <div class="title">
                @Title
            </div>
            <div class="col-lg-4">
                <DarkLightSwitch />
            </div>
        </div>
    </div>
</div>

As you can see, there is another reference to a DarkLightSwitch razor page in the same Blazor component project. This is a simple switch to select a dark mode for the website. If the user clicks on the dark mode, the component has to call a JavaScript function to change the color for the all website.

@inject IJSRuntime jsRuntime

<div class="darkLight-btn">
    <span class="icon @(IsDarkTheme ? "" : "active")" 
        id="light-icon" @onclick="OnLightClick">
        <i class="la la-sun"></i>
    </span>
    <span class="icon @(IsDarkTheme ? "active" : "")" 
        id="dark-icon" @onclick="OnDarkClick">
        <i class="la la-moon"></i>
    </span>
</div>

@code {
    /// <summary>
    /// Is the dark theme activate?
    /// </summary>
    [Parameter] public bool IsDarkTheme { get; set; } = false;

    protected async Task OnLightClick(MouseEventArgs args)
    {
        await jsRuntime.InvokeVoidAsync("switchToLight");
        IsDarkTheme = false;
    }

    protected async Task OnDarkClick(MouseEventArgs args)
    {
        await jsRuntime.InvokeVoidAsync("switchToDark");
        IsDarkTheme = true;
    }
}

When I add the TopNavBar to a MainLayout.razor or any other page, if I click on the DarkLightSwitch nothing is happening because the page is rendered in a static mode.

If in the TopNavBar I call the DarkLightSwitch like this

<DarkLightSwitch @rendermode="RenderMode.InteractiveAuto" />

at run-time the component is not be found.

![enter image description here](/api/attachments/8f0b79cd-20e0-4b8e-8e65-90aed165d925?platform=QnA)

If I add the @rendermode to the TopNavBar, the entire Razor page is not found.

Is there a way to fix it?

1

There are 1 answers

1
MrC aka Shaun Curtis On

I'm making some [major] assumptions based on your description:

You have built a Net8 solution using the Blazor Web App template with InteractiveAuto and Per page/component options selected. You have a third Razor Class Library project containing the components you want to put in a Nuget package.

Here's my version of your DarkLightSwitch. Note mutating parameters within a component is a NONO. I'm assuming IsDarkTheme is the default starting theme, so I've named it as such and only check it on start up to set the internal field.

@inject IJSRuntime JsRuntime

<div>
    <button class="@_buttonCss" @onclick="this.OnClickAsync">@_buttonText</button>
</div>

@code {
    // Allow the parameter to be null if it's not set.
    // You should never set it in code
    [Parameter] public bool IsDefaultDarkTheme { get; set; } = true;

    private bool _isDark;
    private bool _isInitialised;
    private string _buttonCss => _isDark ? "btn btn-light" : "btn btn-dark";
    private string _buttonText => _isDark ? "Switch To Light" : "Switch To Dark";

    public override Task SetParametersAsync(ParameterView parameters)
    {
        parameters.SetParameterProperties(this);

        if (!_isInitialised)
        {
            // only updates if the parameter has a value
            _isDark = this.IsDefaultDarkTheme;
            _isInitialised = true;
        }

        return base.SetParametersAsync(ParameterView.Empty);
    }

    private async Task OnClickAsync()
    {
        if (await JsRuntime.InvokeAsync<bool>("confirm", "Are you sure?"))
            _isDark = !_isDark;
    }
}

This library needs to be referenced by both the Server and Client projects.

MainLayout in the Server project looks like this:

@inherits LayoutComponentBase

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <main>
        <div class="top-row px-4">
            <ComponentLibrary.DarkLightSwitch @rendermode="InteractiveAuto" />
            <a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
        </div>

        <article class="content px-4">
            @Body
        </article>
    </main>
</div>

<div id="blazor-error-ui">
    An unhandled error has occurred.
    <a href="" class="reload">Reload</a>
    <a class="dismiss"></a>
</div>

There's a temporary Repo here.

enter image description here