Skip to content

Commit 4aaeac1

Browse files
preventDefault for form onsubmit handlers. Fixes #951
1 parent 79c60c9 commit 4aaeac1

File tree

4 files changed

+66
-2
lines changed

4 files changed

+66
-2
lines changed

src/Microsoft.AspNetCore.Blazor.Browser.JS/src/Rendering/BrowserRenderer.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { applyCaptureIdToElement } from './ElementReferenceCapture';
88
const selectValuePropname = '_blazorSelectValue';
99
const sharedTemplateElemForParsing = document.createElement('template');
1010
const sharedSvgElemForParsing = document.createElementNS('http://www.w3.org/2000/svg', 'g');
11+
const preventDefaultEvents: { [eventType: string]: boolean } = { submit: true };
1112
let raiseEventMethod: MethodHandle;
1213
let renderComponentMethod: MethodHandle;
1314

@@ -354,15 +355,19 @@ function countDescendantFrames(batch: RenderBatch, frame: RenderTreeFrame): numb
354355
}
355356
}
356357

357-
async function raiseEvent(event: Event, browserRendererId: number, componentId: number, eventHandlerId: number, eventArgs: EventForDotNet<UIEventArgs>) {
358+
function raiseEvent(event: Event, browserRendererId: number, componentId: number, eventHandlerId: number, eventArgs: EventForDotNet<UIEventArgs>) {
359+
if (preventDefaultEvents[event.type]) {
360+
event.preventDefault();
361+
}
362+
358363
const eventDescriptor = {
359364
browserRendererId,
360365
componentId,
361366
eventHandlerId,
362367
eventArgsType: eventArgs.type
363368
};
364369

365-
await DotNet.invokeMethodAsync(
370+
return DotNet.invokeMethodAsync(
366371
'Microsoft.AspNetCore.Blazor.Browser',
367372
'DispatchEvent',
368373
eventDescriptor,

test/Microsoft.AspNetCore.Blazor.E2ETest/Tests/EventTest.cs

+19
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
using Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure.ServerFixtures;
77
using OpenQA.Selenium;
88
using OpenQA.Selenium.Interactions;
9+
using OpenQA.Selenium.Support.UI;
10+
using System;
911
using Xunit;
1012
using Xunit.Abstractions;
1113

@@ -108,5 +110,22 @@ public void MouseDownAndMouseUp_CanTrigger()
108110
actions.Perform();
109111
WaitAssert.Equal("onmousedown,onmouseup,", () => output.Text);
110112
}
113+
114+
[Fact]
115+
public void PreventDefault_AppliesToFormOnSubmitHandlers()
116+
{
117+
var appElement = MountTestComponent<EventPreventDefaultComponent>();
118+
119+
appElement.FindElement(By.Id("form-1-button")).Click();
120+
WaitAssert.Equal("Event was handled", () => appElement.FindElement(By.Id("event-handled")).Text);
121+
}
122+
123+
[Fact]
124+
public void PreventDefault_DotNotApplyByDefault()
125+
{
126+
var appElement = MountTestComponent<EventPreventDefaultComponent>();
127+
appElement.FindElement(By.Id("form-2-button")).Click();
128+
Assert.Contains("about:blank", Browser.Url);
129+
}
111130
}
112131
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<h3>Prevent default</h3>
2+
3+
<p>
4+
Currently we don't call <code>preventDefault</code> by default on DOM events in most cases.
5+
The one exception is for form submit events: in that case, if you have a C# onsubmit handler,
6+
you almost certainly don't really want to perform a server-side post, especially given that
7+
it would occur <em>before</em> an async event handler.
8+
</p>
9+
<p>
10+
Later, it's likely that we'll add a syntax for controlling whether any given event handler
11+
triggers a synchronous <code>preventDefault</code> before the event handler runs.
12+
</p>
13+
14+
<h2>Form with onsubmit handler</h2>
15+
16+
<form action="about:blank" onsubmit=@(() => { })>
17+
<button id="form-1-button" onclick=@HandleClick>Click me</button>
18+
</form>
19+
20+
<h2>Form without onsubmit handler</h2>
21+
22+
<form action="about:blank">
23+
<button id="form-2-button" onclick=@HandleClick>Click me</button>
24+
</form>
25+
26+
@if (didHandleEvent)
27+
{
28+
<p id="event-handled">Event was handled</p>
29+
}
30+
31+
@functions {
32+
bool didHandleEvent;
33+
34+
async Task HandleClick()
35+
{
36+
await Task.Delay(250); // To give time for default action if it's going to occur
37+
didHandleEvent = true;
38+
}
39+
}

test/testapps/BasicTestApp/Index.cshtml

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
<option value="BasicTestApp.AfterRenderInteropComponent">After-render interop component</option>
3535
<option value="BasicTestApp.EventCasesComponent">Event cases</option>
3636
<option value="BasicTestApp.EventBubblingComponent">Event bubbling</option>
37+
<option value="BasicTestApp.EventPreventDefaultComponent">Event preventDefault</option>
3738
<option value="BasicTestApp.RouterTest.TestRouter">Router</option>
3839
</select>
3940

0 commit comments

Comments
 (0)