1
votes

I'm using Blazor Server together with a React app for the layout part.

When Blazor starts up it calls the JSInterop to start up a React component. The React component basically creates a whole bunch of elements inside its layout (the ids of those are provided through the initial call).

My question is how I can tell Blazor to render components into those div-placeholders?

The topics I was able to find always seem to have the html-code of the container being available in Blazor (and then using renderfragment). But in this scenario all I have is the placeholder id - the actual element is not known in Blazor.

Below the code (not using the react library here but instead creating a div within JS so that it's a cleaner example). The main question is around the ***-section that gets called once JS has rendered the div - how can I tell Blazor to acknowledge that div element, or tell Blazor to find it, and to render components into it?

Index.razor

@page "/"
@using Microsoft.Extensions.Configuration
@inject IConfiguration Config
@inject IJSRuntime Jsr
@implements IDisposable

<div></div>

@code {

    private DotNetObjectReference<Index> objectReference;

    [JSInvokable]
    public void SuccessRender(object successrendermessage)
    {
        // ***Here is where it should call the render function.***
    }

    public override Task SetParametersAsync(ParameterView parameters)
    {
        objectReference = DotNetObjectReference.Create(this);
        return base.SetParametersAsync(parameters);
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await Jsr.InvokeVoidAsync("Library.CreateDiv", "uuid1", objectReference);
        }
        await base.OnAfterRenderAsync(firstRender);
    }

    public void Dispose()
    {
        objectReference?.Dispose();
    }
    
}

And here is the JS code:

export function CreateDiv(id, dotNetObj) {
$("body").append("<div id='" + id + "'></div>");
dotNetObj.invokeMethodAsync('SuccessRender', true);
}

1
We won't know how to make the changes to your existing code base without seeing your original code. Please post a minimal reproducible example, and fully explain what needs to be modified. - gunr2171
Apologies - added the code. - klarC
So if I get this right you're using jQuery/React to create a DOM and then have Blazor put data into the manipulated DOM. The problem with such a scenario is about who holds the master version of the DOM. Blazor has no knowledge of the existence of your id div so it can't do anything with it. What's driving you to use React to create the Layout? - MrC aka Shaun Curtis
@MrCakaShaunCurtis I'm trying to use the flexlayout library from react which I like a lot (github.com/caplin/FlexLayout). I haven't found anything as clean in Blazor world. I understand your point but then it would imply that Blazor is always going to expect any JS widget to be the final component without anything nested inside (at least from Blazor's perspective)? Blazor is still the one owning the root. But then react creates a component inside a placeholder div and then within that component I want to place Blazor items. - klarC
@klarC It's almost impossible to "mix" frameworks, because everyone wants to boss the DOM. What you're looking for is a Blazorized version of you favourite layout tool, which probably doesn't exist useless you want to write it. You're probably going to have to make a choice. - MrC aka Shaun Curtis

1 Answers

1
votes

This isn't an answer, but some information as you obviously want to go down this route.

You can in fact have multiple root components on a page.

index.html

add the extra divs with unique ids:

....
    <div id="app">Loading...</div>

    <div id="app1">Loading...</div>

    <div id="app2">Loading...</div>

    <div id="app3">Loading...</div>
....

Program.cs

Add the following:

...
    var builder = WebAssemblyHostBuilder.CreateDefault(args);
    builder.RootComponents.Add<App>("#app");
    builder.RootComponents.Add<SurveyPrompt>("#app1");
    builder.RootComponents.Add<SurveyPrompt>("#app2");
    builder.RootComponents.Add<SurveyPrompt>("#app3");
...

MainLayout.razor (or your own custom Layout set up) it gets used by the first component App

@inherits LayoutComponentBase
@Body

Fire it up and you should get this: enter image description here

All of the ids must exist in the startup page. Each could register with a management service and....