Frodo
Frodo

Reputation: 31

Is it possible to mix Javascript and C# code in a DOM event?

I'm trying to achieve the next in Blazor WebAssembly; I need to be able to listen for an event in a component, and use both Javscript and C# code like the next way:

<button onclick="console.log('Showing event from Js: ' + event); @Test()">Test</button>

@code {
   public void Test()
   {
       JSRuntime.InvokeVoidAsync("console.log", "Showing log from C#");
   }
}

The first problem is that I get the error "cannot implicitly convert type void to object", so if I change the Test method signature just to return an object

public object Test()
{
    JSRuntime.InvokeVoidAsync("console.log", "Showing log from C#");
    return null;
}

The App compiles but once the page is loaded, the "Test()" function is executed automatically, and if I click the button, it just executes the Javascript code, and not both pieces of code.

I know I should handle events in Blazor prefixing the event name with "@" symbol in order to call a C# method, and execute Javascript code there using the interop, but in that way, I can't use the default Javascript "event" which I need to use, instead of the Blazor "event" version.

Thanks in advance!

Upvotes: 3

Views: 700

Answers (2)

Chris F Carroll
Chris F Carroll

Reputation: 12370

There are perhaps 3 different ways you can fire both C# and javascript handlers for one DOM event.

1. Rely on Event Bubbling

Wrap your button in a div or span. Put the javascript onclick on the containing div or span, and leave the C# onclick on the button.

<div onclick="console.log('Showing event from Js: ' + event)>
<button @onclick="Test">Test</button>
</div>

As well as mouse events and most key events, the DOM will also bubble select, change, and some other events


2. Use EventListeners

You can have both JS and C# fire on the same DOM event by placing the C# as an inline attribute as normal, but adding the javascript as an event listener.

For instance at the bottom of your App.razor or _Host.cshtml <body>

    <script src="_framework/blazor.web.js"></script>
    <script>        
        document.addEventListener("click", function(e){
            if (e.target.id !== "testButton")return
            console.log("You clicked ", e.target.innerText)
            })

You may need to look up, “how to add event listeners to dynamically generated elements.”


  1. Use a "good enough" spare event

Inline, with varying degrees of correctness, you can sometimes use a "spare" javascript event, several of which will fire on the same element at nearly the same time. But I don't have a compelling example of when you would choose this over option 1, event bubbling.

<input @onchanged="Test" onblur="javascript:…" />
<input @oninput="Test" onkeyup="javascript:…" />
<select @onchanged="Test" oninput="javascript:…">...</select>
<select @bind="Test" oninput="javascript:…">...</select>
<button @onclick="Test" onmouseup="javascript:…">...</button>

Upvotes: 1

Henk Holterman
Henk Holterman

Reputation: 273294

You can only have 1 onclick attribute, so either call the C## method from JS or call the JS code from C#. In both cases you will need Interop, there is no support for combining this in the way you are trying to.

the "Test()" function is executed automatically

Yes, in onclick="... @Test()" it is executed when the page renders, not when the button is clicked.

Upvotes: 1

Related Questions