.net-coreblazor-webassemblyfroala

blazor IJSRuntime How to function (clickEvent) { ... }


I'm building an application with Froala HTML Editor. The basic functionality I get to work, however I did not succeed in the Events part.

The following code is for JavaScript (Froala doc)

new FroalaEditor('.selector', {
  events: {
   'contentChanged': function () {
     // Do something here.
     // this is the editor instance.
     console.log(this);
   }
  }
});

The code I got working looks like this

var config = new FroalaEditorConfig()
    {
         ToolbarInline = true,
         CharCounterCount = false,
         Key = KEY,
    };
await JsRuntime.InvokeVoidAsync("FroalaEditor", ".selector", config);

I tried to add the following arguemtn after Key

Events = new Dictionary<string, string>
   {
       {"contentChanged", "function () { DotNet.invokeMethodAsync('PubbleCloud.Frontend.Client', 'PubbleCloud.Frontend.Client.Shared.Form.ContentChanged'); }"},
       {"click", "function () { DotNet.invokeMethodAsync('PubbleCloud.Frontend.Client', 'PubbleCloud.Frontend.Client.Shared.Form.Click'); }"}
   }

This returns the error: Uncaught TypeError: l.opts.events[e].apply is not a function

where I created the following function and tried both with static and object functions.

[JSInvokable]
public static void ContentChanged()
{
    Console.WriteLine("ContentChanged");
}

Is there any way I can add a call to my blazor functions?


Solution

  • I have found a solution, I'm not happy about it yet, but it works.

    I would love to know if there is a way to do this without a separate js file.

    First you need to create a js file.

    dotNetHelper = null;
    
    function setDotNetHelper(value) {
        dotNetHelper = value;
    }
    
    function createEditor(el) {
        return new FroalaEditor(el,
            {
                toolbarInline: true,
                charCounterCount: false,
                events: {
                    'contentChanged': function () {
                        dotNetHelper.invokeMethodAsync('ContentChanged');
                    },
                    'click': function () {
                        dotNetHelper.invokeMethodAsync('Click');
                    }
                }
            }
        );
    }
    

    The blazor object looks like thisFroalaEditor.razor.cs

    public sealed partial class FroalaEditor : IDisposable
    {
        [Inject] private IJSRuntime JsRuntime { get; set; } = default!;
        [Parameter] public RenderFragment? ChildContent { get; set; }
        private DotNetObjectReference<FroalaEditor>? dotNetHelper;
        private CancellationTokenSource _cts = new();
    
        private string _froalaId = "froala-editor";
    
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                dotNetHelper = DotNetObjectReference.Create(this);
                await JsRuntime.InvokeVoidAsync("setDotNetHelper",  dotNetHelper);
                await JsRuntime.InvokeVoidAsync("createEditor", _cts.Token, $"#{_froalaId}");
            }
        }
        
        [JSInvokable]
        public void ContentChanged()
        {
            Console.WriteLine("ContentChanged");
        }
    
        [JSInvokable]
        public void Click()
        {
            Console.WriteLine("Click");
        }
    
        public void Dispose()
        {
            _cts.Cancel();
            dotNetHelper?.Dispose();
        }
    }
    

    And to be complete, the razor file looks like this.

    <div id="@_froalaId">
        @ChildContent
    </div>
    

    EDIT: I have build a NuGet with this solution: github