Author : MD TAREQ HASSAN | Updated : 2020/09/07

Call JavaScript from Blazor



Bootstrap toast in ‘Shared/MainLayout.razor

@inherits LayoutComponentBase

<!-- removed for brevity -->

<div class="container" style="position: relative;">

    <div class="toast mt-sm-2 fade hide" data-delay="2500" role="alert" aria-live="assertive" aria-atomic="true" style="position: absolute; top: 0; right: 0; z-index:1000; min-width: 25%;">
        <div class="toast-header bg-success text-white">
            <strong class="mr-sm-auto">Success</strong>
            <button type="button" class="ml-2 mb-1 close text-white" data-dismiss="toast" aria-label="Close">
                <span aria-hidden="true">&times;</span>
            </button>
        </div>
        <div class="toast-body"></div>
    </div>
	
    <main role="main" class="pb-3">
        @Body
    </main>
</div>

Notes:



<script>’ tag in ‘Pages/_Host.cshtml

@page "/"

<!-- removed for brevity -->

<!DOCTYPE html>
<html lang="en">
<head>

    <!-- removed for brevity -->

    <script>
        window.JSInterop = {

            ShowToast: function (toastId, toastMessage) {

                console.log(`showing toast for id: "${toastId}"`);

                $('.toast-body').text('');
                $('.toast-body').text(toastMessage);
                $(toastId).toast('show');
            }
        };
    </script>

</head>
<body>

    <!-- removed for brevity -->
	
</body>
</html>



See: CrudOperation enum: useful-extension#navigationmanagerextention
BaseComponent.cs

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.JSInterop;
using Serilog;
using System;
using System.Linq;


public class BaseComponent: ComponentBase
{

	[Inject]
	protected NavigationManager NavigationManager { get; set; }

	[Inject]
	IJSRuntime JSRuntime { get; set; }


        protected async Task ShowToastMessageIfNeeded()
        {
            var uri = NavigationManager.ToAbsoluteUri(NavigationManager.Uri);

            var parsedQuery = QueryHelpers.ParseQuery(uri.Query);

            //
            // Look for a single query param that indicates crud operation flag
            //
            if ((parsedQuery?.Any()).HasValue && parsedQuery.Count == 1)
            {

                var performedOperation = parsedQuery.First().Key;

                // need to check if redirection happended from a valid page
                if (Enum.IsDefined(typeof(CrudOperation), performedOperation))
                {
                    // show toast
                    var toastMessage = $"Item {performedOperation}";
                    await JSRuntime.InvokeVoidAsync(Interop.ShowToast, ".toast", toastMessage);
                }
                else
                {
                    Log.Warning("Unknown query parameter (not a crud operation flag)");
                }
            }
        }
	
	protected void PerformRedirection(CrudOperation @for)
	{
		NavigationManager.NavigateTo($"/items?{@for}");
	}
}



Usage: Delete.razor.cs

using Microsoft.AspNetCore.Components;
using System.Threading.Tasks;


public class DeleteBase : BaseComponent
{
	[Parameter]
	public int Id { get; set; }

	protected Item Item = new Item();
	
	
	// ... ... ...


	protected override async Task OnInitializedAsync()
	{
		Item = await Service.FindItemAsync(Id);
	}

	protected async Task PerformDeletion()
	{

		var success = await Service.DeleteItemAsync(Id);
		if (!success)
		{
			ErroMessage = "Failed to Delete Item";
			return;
		}

		PerformRedirection(@for: CrudOperation.deleted);
	}
}

If delete operation is successful:

Call Blazor from JavaScript

Using static delegate

delete.razor.cs

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop;
using System;
using System.Threading.Tasks;

    public class DeleteBase : BaseComponent
    {
        [Parameter]
        public int Id { get; set; }

        protected FooModel FooModel { get; set; } = null;
		
		
		
        #region JSInterop

        protected static Func<Task> DeleteFunc { get; set; }

        [JSInvokable]
        public static async Task DeleteFoo()
        {
            await DeleteFunc?.Invoke(); // await DeleteFunc?.Invoke(params...);
        }

        #endregion
		
		

        protected override async Task OnInitializedAsync()
        {

            DeleteFunc = PerformDeletion;

            try
            {
                DbContext = DbContextFactory.CreateDbContext();

                FooModel = await FindFooAsync(Id);
            }
            catch (AppException ex)
            {
                // ... ... ...
            }

        }


        protected async Task PerformDeletion()
        {
            // ... ... ...

            var entryExists = await IsFooAlreadyExist(Id);
            if (!entryExists)
            {
                
				// Error...
				
                return;
            }

            try
            {
                var fooToDelete = await DbContext.Foos.FindAsync(Id);
                DbContext.Foos.Remove(fooToDelete);
                await DbContext.SaveChangesAsync();

                NavigationManager.NavigateTo("/items?deleted");
 
            }
            catch (Exception)
            {
                // ... ... ...
            }
        }
    }

Using event

wwwroot/js/foo.js

window.barWindowObject = {

    bazz: function (elementId, width, height) {
	
        // ... ... ...
		
    },

    bax: function (...) {

        // ... ... ...
    }
}

Javascript.cs

using Microsoft.JSInterop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace FooNameSpace
{
    public static class Javascript
    {
	
		public static event Action FooEventHandler;
		
		// ... ... ...
		
        [JSInvokable]
        public static Task FireFooEvent()
        {
            return Task.Run(() => FooEventHandler?.Invoke());
        }
    }
}

Pages/foo.cshtml

@page "/settings"
@inject FooService fs
@implements IDisposable

// ... ... ...


<button id="fooBtn" onClick="barWindowObject.bax"></button>


@functions{
    
	// ... ... ...
	
    void OnFiredFooEvent()
    {
        //count++;
		
		// ... ... ...
		
        StateHasChanged();
    }
	
    protected override void OnAfterRender()
    {
        base.OnAfterRender();
        
        Javascript.FooEventHandler += OnFiredFooEvent;
    }

    public void Dispose()
    {
        Javascript.FooEventHandler -= OnFiredFooEvent;
    }
}

<script>
window.barWindowObject = {

    // ... ... ...
	
    bax: function (...) {

        // ... ... ...
		
        // when some condition met
        DotNet.invokeMethodAsync("FooNameSpace", "FireFooEvent");
    }
}
</script>