Reputation: 887
I try to implement a simple onclick event handler like this sample, but it is not working in my solution. The event is only triggered at the run of the web page for unknown reasons.
The HTML page with Blazor component is well shown, but when I click on the button, nothing is happening.
I'm on Visual Studio 2019 and .NET Core 3.0, with an ASP.NET MVC project.
@using Microsoft.AspNetCore.Components
<p>Current count: @currentCount</p>
<button class="btn btn-primary" onclick="@IncrementCount();">Click me</button>
@code {
int currentCount = 0;
private async Task IncrementCount()
{
await Task.Run(() => currentCount++);
}
}
@using WebApplication2.Views.Components
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
@(await Html.RenderComponentAsync<Counter>(RenderMode.Server, new { }))
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddHttpClient();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change
// this for production scenarios; see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapBlazorHub();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
The button in the browser:
<button class="btn btn-primary" onclick="System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.Threading.Tasks.VoidTaskResult,WebApplication2.Views.Components.Counter+<IncrementCount>d__2];">Click me</button>
The error in the browser:
Upvotes: 77
Views: 114991
Reputation: 1
I use .NET 8 and this work for me
@rendermode @(new InteractiveServerRenderMode(prerender: false))
Put this on the top of your component and this work for me:)
Upvotes: 0
Reputation: 5734
I resolved the issues by adding @rendermode InteractiveServer in razor page.
Upvotes: 7
Reputation: 61
I'm using WebAssembly .net8. For this to work on server-side pages, was necessary to include .AddInteractiveServerComponents() and .AddInteractiveServerRenderMode() on the Program.cs
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents()
.AddInteractiveWebAssemblyComponents();
and
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode()
.AddInteractiveWebAssemblyRenderMode()
.AddAdditionalAssemblies(typeof(SiteCasamento.Client._Imports).Assembly);
and than include rendermode in the pages
@rendermode InteractiveServer
Thanks
Upvotes: 6
Reputation: 37895
This answer is only for .net 8, where static rendering is the default. .net 8 introduced the notion of Render Modes, and it is now required either at the page level, or globally. The default is static rendering which means that the component is rendered exactly as it is written with no interactivity being wired up by the Blazor engine. This is nice if you have pure static html, and don't need the overhead of the interactivity. On the other hand, it can catch you by suprise if have used earlier version and your click event is just not getting processed and there is no obvious reason for it.
To wire up interactivity, you have two options.
Per component solution
Check for this directive at the top of the file:
@rendermode InteractiveServer
If it's missing, then you will not get events being fired. On the client side (wasm) it will be this:
@rendermode InteractiveAuto
Global solution
Update Routes
element in App.razor
file:
<body>
<Routes @rendermode=RenderMode.InteractiveServer />
<script src="_framework/blazor.web.js"></script>
</body>
The Global solution allows you to use interactive elements in the MainLayout.razor
which is not supported in the per component solution. This can be useful if you are doing something like wiring up a "dark" mode and need a class to be applied at the top level of your html so it gets applied to everything.
Edit: Even though you have added AddInteractiveServerComponents()
this does NOT mean that you have set the default to be InteractiveServer. It only means that you have the option to add InteractiveServer as a global or component option. So you still must add the global or component option as above.
Upvotes: 157
Reputation: 1
This fixed my issue. I just hide the unwanted buttons instead of adding and removing them.
<MudItem sm="4" Style="padding-top:30px">
<MudButton style="@ScheduleAddButton" Color="Color.Warning" Variant="Variant.Outlined" OnClick="() => SaveSchedule()">Add Schedule</MudButton>
<MudButton style="@ScheduleRemoveButton" Color="Color.Warning" Variant="Variant.Outlined" OnClick="() => DeleteSchedule()">Delete Schedule</MudButton>
</MudItem>
Added code
if (Schedule.Trim().Length == 0)
{
ScheduleAddButton = "display:block";
ScheduleRemoveButton = "display:none";
}
else
{
ScheduleAddButton = "display:none";
ScheduleRemoveButton = "display:block";
}
StateHasChanged();
Upvotes: 0
Reputation: 67
Much like DreamEvil 's answer, I was having this problem after I added StaticFileOptions
to my app.UseStaticFiles()
method in Program.cs.
I stumbled across this known Blazor issue which explains the problem: Passing options to UseStaticFiles breaks Blazor Server's static file service #19578
There are a couple of solutions, but my favorite is by configuring StaticFileOptions
in the Services collection before calling app.UseStaticFiles()
(without any parameters).
builder.Services.Configure<StaticFileOptions>(options =>
{
options.OnPrepareResponse = ctx=>
{
const int durationInSeconds = 60 * 60 * 24 * 7;
ctx.Context.Response.Headers[HeaderNames.CacheControl] =
"public,max-age=" + durationInSeconds;
};
});
Upvotes: 1
Reputation: 938
Maybe learn the difference between a return value of an executed method and a method-type aka as delegate e.g. Action
IncrementCount(); // Is a method that returns void (or string, or a Task, if you want)
var returnValue = MyMethod2();
// These declare and initialize delegate variables
var action = IncrementCount;
var action2 = MyMethod;
Func<int> myFunc = MyMethod2;
MyDelegate myDel = MyMethod3;
You want to provide a delegate to the @onclick
directive, ... not use the old syntax, nor a return value (although it’s possible)
<button @onclick=@Hahaha()>Click me</button>
<button @onclick=@Foo>Click me</button>
<button onclick="console.log('Hahaha Foo')">Click me</button>
<button onclick=@Baar()>Click me</button>
@code {
Action Hahaha(){
return Foo;
}
void Foo() {
i = 5;
}
}
string Baar()
{
return "console.log('Boofar')";
}
The code onclick="@IncrementCount();"
is simply dead wrong in at least three ways.
"
if you dont wanna provide a string;
if there is no block
at all -> learn about the @ directive
The framework does exactly what you tell it todo:
casting the Task into a string with the implicit ToString(), append a ';' and pass that as the JavaScript code for the html attribute onlick
which gets exactly rendered as that. Note that this even only works for non-void methods, because void methods would not even return anything and thusly cannot used as an expression
for a string, what is what is inferred here!
Upvotes: 0
Reputation: 211
Use:
<button class="dropdown-item" type="button" @onclick="() => lock_invoice(r)"> <i class="fa fa-lock"></i> Lock</button>
And code:
@code {
void lock_invoice(System.Data.DataRow row)
{
string id = row["id"].ToString();
...
}
}
Upvotes: 0
Reputation: 1638
I tried to figure out most of the solutions for Blazor inside the ASP.NET MVC application. Some are incomplete, so I’ve tried to prepare complex instructions which work for me. If you are working on Blazor inside an ASP.NET MVC application, you have to do the following stuff.
Go to the _Layout.cshtml or index.html and in the bottom script section, add
<script src="~/_framework/blazor.server.js"></script>
In the same file, _Layout.cshtml or index.html, in the head tag section right after the title or meta tags, add:
<base href="/" />
Or alternatively
<base href="~/"/>
Create the _Imports.razor file inside your Blazor components directory and add to it following using statements:
@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
Alternatively, you can add these statements directly at the beginning of your component file.
Use onclick as follow:
If you want to pass parameters:
@onclick="(()=>YourEvent(yourParams))"
Or simply if you just want to call:
@onclick="YourEvent"
Upvotes: 3
Reputation: 1025
The solution for me ended up being quite a bit different than the other answers here. I was using Cloudflare CDN to help serve my Blazor Server application.
In the end, I needed to turn off 'HTML Minification' in Cloudflare to get my onclick events working again.
Turn this setting 'off' in Cloudflare in the 'Speed' settings section:
For additional options for getting around the issue, please reference this blog post:
I also ran into this same HTML Minification issue using Scully with Angular and Cloudflare.
Additional helpful blog post: Blazor Server events not triggering when hosted behind Cloudflare
Upvotes: 3
Reputation: 463
I had all my Blazor components in a separate "class library" project.
Including @using Microsoft.AspNetCore.Components.Web in the component solved the issue.
Upvotes: 1
Reputation: 107
I had the same problem. The problem was running the app in Internet Explorer.
OnClick worked fine when I ran the app in Edge.
Upvotes: -2
Reputation: 189
In my case, I added StaticFileOptions in file Startup.cs like this (I used this code in my ASP.NET Core project):
app.UseStaticFiles(new StaticFileOptions()
{
OnPrepareResponse = ctx =>
{
const int duration = 60 * 60 * 24;
ctx.Context.Response.Headers[HeaderNames.CacheControl] = $"public,max-age={duration}";
}
});
Then I returned to
app.UseStaticFiles();
and it started to work.
Upvotes: 2
Reputation: 9475
I had the exact same issue, but I found the solution in onclick method is not working in Blazor server-side Razor component.
You need to add a _Imports.razor
file into your Components folder with the following using statements.
@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
Upvotes: 15
Reputation: 3697
This is the most popular question related to the problem: Blazor onclick events don't get triggered. Adding to the answers that resolved the OP's problem and were unable to resolve mine, I would like to add that:
<script src="~/_framework/blazor.server.js"></script>
need to be placed after the component that declares the events, not in the <head />
tag. Possibly at the very bottom of the body
tag of _Host.cshtml
or your MVC View that needs Blazor
components. If you don't do it, Blazor syntax will still work, the project will compile and most things will behave as expected, but the events won't be triggered.
I just spent hours trying to figure that out.
Also if @onclick
is not recognised as Blazor code in .razor files at all (this can happen especially in Component Libraries), make sure to add _Imports.razor
at the very top of the project with the following content:
@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
If for some reason some of the namespaces can't be found, they can be added as NuGet packages.
Upvotes: 51
Reputation: 1005
I just noticed you are embedding this in an MVC application. You don't have the script tag to it for blazor.server.js in the index.cshtml. In it you add
<script src="_framework/blazor.server.js"/>
at the bottom of the index.cshtml page. This is what wires up SignalR to the server, which is needed for server side.
See Scott Hanselman doing exactly what you are trying to do.
Upvotes: 0
Reputation: 1005
I think your call to the onclick event is wrong. They changed the way you reference functions from
<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>
to
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
The @
is now in front of the @onclick
and not in front of the function name.
Upvotes: 33
Reputation: 2323
Changing RenderMode.Static
to RenderMode.Server
will probably solve your problem since you use server-side Blazor. But as JohnB suggested, you should read the documentation. Learn about the difference between server-side Blazor and client-side Blazor at ASP.NET Core Blazor hosting models.
Upvotes: 2
Reputation: 827
Try add @ at onclick like this
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
Thanks Joon
Upvotes: 1
Reputation: 983
I've just had a very strange case of this problem: this code wasn't triggered.
<div ... @onclick=@(_ => OnClick.InvokeAsync(EventArgs.Empty))></div>
The problem's root is still unclear, but the solution (or rather a workaround) was to replace lambda with a method name.
<div ... @onclick=OnClickHandler></div>
@code {
private void OnClickHandler()
{
OnClick.InvokeAsync(EventArgs.Empty);
}
}
Upvotes: 3
Reputation: 13
I was stuck all day with this problem and then discovered that was working just fine in Chrome. Therefore, I added http://localhost to my list of Intranet websites in the Windows 10 Control Panel / Internet Settings / Security page. This only needs to be done for developers running the app from Visual Studio.
Upvotes: 0