Aspnetcore: Trigger a js custom event after Blazor boot complete

Created on 16 Mar 2018  路  8Comments  路  Source: dotnet/aspnetcore

I need to register some javascript functions (using Interop.registerFunction.ts), but currently I can't because window ['Blazor'].registerFunction is made available only after booting.

Is it possible to insert a 'BlazorOnLoad' event after boot() in boot.ts?

area-blazor enhancement

Most helpful comment

Is it possible to raise events to the browser as blazor is fetching each resource resource prior to calling the entry point? to drive an HTML splash screen/loading progress ....

events with name of resource, size, bytes loaded ...

All 8 comments

Yes, that's a good idea. We'll do it.

Actually to clarify, if your goal is to call Blazor.registerFunction, you should do that before Blazor has booted. Otherwise if there was some synchronous code in Program::Main that wanted to call your JS function, it wouldn't be able to.

So the usual pattern is:

<script type="blazor-boot"></script>
<script>
    Blazor.registerFunction(...) // Or put this in an external .js file and load it below the "blazor-boot" script
</script>

Then your function will definitely be registered before the .NET app starts (because Blazor always boots asynchronously, because it involves fetching resources over the network).

Summary:

  • If you want to call Blazor.registerFunction, you don't need any new event (nor should you use one)
  • There is still a different use case for a 'BlazorOnLoad' event, though, which is if you want to call some .NET code from JS as soon as the .NET runtime has started. So we'll still add the event, but you shouldn't use it for Blazor.registerFunction.

Is it possible to raise events to the browser as blazor is fetching each resource resource prior to calling the entry point? to drive an HTML splash screen/loading progress ....

events with name of resource, size, bytes loaded ...

Is currently a way to know when it is safe to interop from .NET to JS? If I do it in OnInit then it doesn't work as it throws in

Error: Microsoft.AspNetCore.Blazor.Browser.Interop.JavaScriptException: a is undefined

If anybody is interested, I have a workaround. I call into js in a try/catch loop until it doesn't throw anymore.
When an exception is thrown, I wait for a certain TimeSpan to not hammer it.

I know this is ugly but this is what I put together to display progress of my app loading. It will do a percentage then show a count of the required files downloading. Useful for slow connections.

I will look into picking this enhancement up and submitting a PR as this is what I was looking for and there were a few spots I felt emitting an event would help.
Preview

<app>
    <style>
        app {
            position: static;
        }
    </style>
    <div>
        <div class="loading-text">
            <small id="Loading-text">Loading</small>
            <small id="Progress-report">0%</small>
        </div>
    </div>
</app>
<script>
    (function bootLoader() {

        var fetchListener = window.fetch,
            perf = window.performance.timing,
            el = document.getElementById('Progress-report'),
            progress = 0,
            timer = setInterval(function() {
                el.innerText = ++progress + '%';
                if (progress >= 100) {
                    clearInterval(timer);
                    bootSequence();
                }
            }, Math.abs(Math.floor(((perf.loadEventEnd - perf.navigationStart) / 1e3) % 60))),
            assemblyReferences = [];


        window.fetch = function() {
            var result = fetchListener.apply(this, arguments);
            if (arguments[0] === '_framework/blazor.boot.json')
                result.then(function(response) {
                    response.clone().json().then(function(bootConfig) {
                        assemblyReferences = bootConfig.assemblyReferences;
                    });
                });
            return result;
        }

        function bootSequence() {
            if (window['MONO'] && MONO.mono_wasm_runtime_is_ready) return;
            document.getElementById('Loading-text').style.display = 'none';
            el.innerText = 'Initializing';
            var bootWatch = setInterval(function() {
                if (assemblyReferences.length == 0 || !window['MONO']) return;
                el.innerText = 'Booting';
                if (!MONO.loaded_files) return;
                el.innerText = 'Fetching ' + MONO.loaded_files.length + '/' + assemblyReferences.length;
                if (assemblyReferences.length === MONO.loaded_files.length) {
                    el.innerText = 'Rendering';
                    clearInterval(bootWatch);
                }
            }, 50);
        }
    })();
</script>

This has changed significantly since this issue was filed. Blazor.registerFunction and you can use await blazor.start to execute scripts before and after blazor has loaded.

Was this page helpful?
0 / 5 - 0 ratings