4

I want render a Blazor component from javascript. See https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-1/ "Render Blazor components from JavaScript"

I have a HTML file:

<script src="/_framework/blazor.server.js"></script> <div id="counter"></div> <script> async function ready() { let containerElement = document.getElementById('counter'); await Blazor.rootComponents.add(containerElement, 'counter', { incrementAmount: 10 }); } document.addEventListener("DOMContentLoaded", ready); </script> 

And do

builder.Services.AddServerSideBlazor(options => { options.RootComponents.RegisterForJavaScript<Counter>("counter"); }); 

Error message (JavaScript):

test.html:14 Uncaught (in promise) Error: Dynamic root components have not been enabled in this application. at E (blazor.server.js:1) at Object.add (blazor.server.js:1) at HTMLDocument.ready (test.html:8) 

How can i enable dynamic root components?

1

1 Answer 1

9

The error is happening because of the delay between the document loading and Blazor being "ready" to process your request to add a component.

There doesn't appear to be any official documented solution for this, but something like this is possible

Change Blazor to manual start:

index.html

<script src="_framework/blazor.webassembly.js" autostart="false"></script> <script src="js/script.js" defer></script> 

Start Blazor, then try to add components - repeat until success

script.js

document.addEventListener("DOMContentLoaded", startBlazor) function startBlazor() { Blazor .start() .then(() => { requestAnimationFrame(AddBlazorComponents) }) .catch((error) => console.error(error)); } let attempts = 0 const maxAttempts = 120 // arbitrary choice function AddBlazorComponents() { if (attempts > maxAttempts) { // give up after trying too many times console.error("Could not load Blazor components.") return } const containerElement = document.querySelector('#app') Blazor.rootComponents.add(containerElement, 'app', {}) .catch(reason => { if (reason.message === "Dynamic root components have not been enabled in this application.") requestAnimationFrame(AddBlazorComponents) else console.error(reason) }) attempts++ } 

Better solution?

You could, possibly, add a JSInterop call to your .NET code to facilitate this, after the application starts - but it would be different for the different hosting models : Blazor Server / Blazor WebAssembly.

Even better might be to make a PR to the aspnetcore repo with a method of pre-registering components for the framework to load when it is ready.

Update 29 sep 2021

It turns out there is some currently undocumented functionality that helps here. I have copied my comment from @Swimburger 's github issue below:

The new JavaScript Initializer afterStarted is called (potentially) too soon for Dynamic components, but it turns out you can pass an initializer to be called for a dynamic component - but it is not well documented or intuitive imho.

To make this work, I changed the app startup like this (adding javaScriptInitializer: "loadApp") in program.cs:

builder.RootComponents.RegisterForJavaScript<App>(identifier: "app", javaScriptInitializer: "loadApp");

Then, and this is where it was non-intuitive, I added an export to my module (like afterStarted) called loadApp - but it wasn't called.

It turned out that loadApp is only found if I add it to the window object, so I added this to index.html

<script src="_framework/blazor.webassembly.js"></script> <script> window.loadApp = function (component,params) { let containerElement = document.querySelector('#app') window.Blazor.rootComponents.add(containerElement, component, params) } </script> 

This feels like I am missing something in how to export my custom initializer OR it really does need to be added to window directly, which seems odd...

5
  • When I try this, I don't need to request animation frame logic to keep trying. It always works on the first try. gist.github.com/Swimburger/c808f10bcb2c022c624aca233beecca1 Thank you for this solution!CommentedSep 28, 2021 at 22:11
  • I also created an issue on GitHub to see if we can make this more intuitive: github.com/dotnet/aspnetcore/issues/37074CommentedSep 28, 2021 at 23:01
  • @Swimburger I think you have been lucky or possibly using a different browser - I actually wrote/tested this using your github repo and definitely needed the retry logic - usually about 2 or 3 attempts before it was ready.CommentedSep 28, 2021 at 23:43
  • Odd, it always loads correctly every time I try it. I tried it in Chrome, Edge, and Firefox. I haven't tried on Safari. I also tried with slow 3G emulation in Chrome and no issues. Could you give more details about your browser?CommentedSep 29, 2021 at 4:30
  • I was using Edge/Chrome/Firefox - I added a console log to AddBlazorComponents and saw it was logging 2/3 timesCommentedSep 29, 2021 at 8:57

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.