TameemHabash
TameemHabash

Reputation: 108

Passing Cascading Parameters to Blazor component that rendered from JavaScript

I want to pass a CascadingParameter to the Counter page component, but I don't want to use the router. Instead of that, I want to use JavaScript because I want the component to be rendered inside the window of Winbox.js (open-source HTML5 window manager).

The problem is that Cascading Parameters are initialized as null, I think it's happened due to the difference in RenderTree.

Here is my code:

Registration of Counter.razor component for JavaScript in Program.cs:

builder.RootComponents.RegisterForJavaScript<Counter>(identifier: "counter");

For MainLayout.razor

<!-- omitted for brief -->
        <CascadingValue Value="_TestCascadingParameter">
            <article class="content px-4">
                @Body
            </article>
        </CascadingValue>
<!-- omitted for brief -->
@code{
private TestCascadingParameter _TestCascadingParameter = new() { GlobalCounter = 5 };

public class TestCascadingParameter
{
    public int GlobalCounter { get; set; }
}

For Counter page:

@page "/counter"
@using static BlazorApp1.Shared.MainLayout

    <PageTitle >Counter</PageTitle>
    <h1>Counter</h1>

    <p role="status">Current count: @currentCount</p>

    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>



@code {
    [CascadingParameter]
    public TestCascadingParameter TestCascadingParameter { get; set; }
    private int currentCount = 0;

    protected override void OnParametersSet()
    {
        currentCount = TestCascadingParameter.GlobalCounter;
    }

    private void IncrementCount()
    {
        currentCount++;
    }
}

For Winbox page:

@page "/WinBox"
@layout MainLayout
@inject IJSRuntime _Js
<PageTitle>Win box</PageTitle>

<button @onclick="@OpenWinAsync">Open window</button>

@code{
    async Task OpenWinAsync()
    {
        await _Js.InvokeVoidAsync("MyWinBox.OpenTestWindow");
    }
}

And for MyWinBox.js:

window.MyWinBox = {
    OpenTestWindow: async () => {
        let containerElement = new WinBox("WinBox.js");
        await Blazor.rootComponents.add(containerElement.body, 'counter', {});
    }
};

When I navigate to Counter page using router everything works fine and the currentCount starts from 5, but when I use JavaScript to render it, it throws a NullReferenceException on TestCascadingParameter.

How to solve this without passing Cascading Parameter value through JavaScript because sometimes the Cascading Parameter has a null value in the caller component as in the above example (eg: if caller component is MudDialog) or sometimes there is more than one Cascading Parameter.

Upvotes: 0

Views: 1273

Answers (1)

szmp
szmp

Reputation: 114

RegisterForJavaScript is new, not well-documented feature and I can't tell if it's possible to pass cascading parameter like that. But I think that you can use State container (or something like Fluxor) to achieve your goals:

public class StateContainer
{
    private int? globalCounter;

public int Property
{
    get => globalCounter;
    set
    {
        globalCounter = value;
        NotifyStateChanged();
    }
}

public event Action? OnChange;

private void NotifyStateChanged() => OnChange?.Invoke();
}

More details here: https://learn.microsoft.com/en-us/aspnet/core/blazor/state-management?view=aspnetcore-6.0&pivots=webassembly

Upvotes: 1

Related Questions