From 4aaeac1e51d5985344df7220ee17c4b0b81bcf73 Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Mon, 23 Jul 2018 11:02:50 -0700 Subject: [PATCH] preventDefault for form onsubmit handlers. Fixes #951 --- .../src/Rendering/BrowserRenderer.ts | 9 ++++- .../Tests/EventTest.cs | 19 +++++++++ .../EventPreventDefaultComponent.cshtml | 39 +++++++++++++++++++ test/testapps/BasicTestApp/Index.cshtml | 1 + 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 test/testapps/BasicTestApp/EventPreventDefaultComponent.cshtml diff --git a/src/Microsoft.AspNetCore.Blazor.Browser.JS/src/Rendering/BrowserRenderer.ts b/src/Microsoft.AspNetCore.Blazor.Browser.JS/src/Rendering/BrowserRenderer.ts index 9da226a6ed..5015384e08 100644 --- a/src/Microsoft.AspNetCore.Blazor.Browser.JS/src/Rendering/BrowserRenderer.ts +++ b/src/Microsoft.AspNetCore.Blazor.Browser.JS/src/Rendering/BrowserRenderer.ts @@ -8,6 +8,7 @@ import { applyCaptureIdToElement } from './ElementReferenceCapture'; const selectValuePropname = '_blazorSelectValue'; const sharedTemplateElemForParsing = document.createElement('template'); const sharedSvgElemForParsing = document.createElementNS('http://www.w3.org/2000/svg', 'g'); +const preventDefaultEvents: { [eventType: string]: boolean } = { submit: true }; let raiseEventMethod: MethodHandle; let renderComponentMethod: MethodHandle; @@ -354,7 +355,11 @@ function countDescendantFrames(batch: RenderBatch, frame: RenderTreeFrame): numb } } -async function raiseEvent(event: Event, browserRendererId: number, componentId: number, eventHandlerId: number, eventArgs: EventForDotNet) { +function raiseEvent(event: Event, browserRendererId: number, componentId: number, eventHandlerId: number, eventArgs: EventForDotNet) { + if (preventDefaultEvents[event.type]) { + event.preventDefault(); + } + const eventDescriptor = { browserRendererId, componentId, @@ -362,7 +367,7 @@ async function raiseEvent(event: Event, browserRendererId: number, componentId: eventArgsType: eventArgs.type }; - await DotNet.invokeMethodAsync( + return DotNet.invokeMethodAsync( 'Microsoft.AspNetCore.Blazor.Browser', 'DispatchEvent', eventDescriptor, diff --git a/test/Microsoft.AspNetCore.Blazor.E2ETest/Tests/EventTest.cs b/test/Microsoft.AspNetCore.Blazor.E2ETest/Tests/EventTest.cs index a5db339ef5..db719228bb 100644 --- a/test/Microsoft.AspNetCore.Blazor.E2ETest/Tests/EventTest.cs +++ b/test/Microsoft.AspNetCore.Blazor.E2ETest/Tests/EventTest.cs @@ -6,6 +6,8 @@ using Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure; using Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure.ServerFixtures; using OpenQA.Selenium; using OpenQA.Selenium.Interactions; +using OpenQA.Selenium.Support.UI; +using System; using Xunit; using Xunit.Abstractions; @@ -108,5 +110,22 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests actions.Perform(); WaitAssert.Equal("onmousedown,onmouseup,", () => output.Text); } + + [Fact] + public void PreventDefault_AppliesToFormOnSubmitHandlers() + { + var appElement = MountTestComponent(); + + appElement.FindElement(By.Id("form-1-button")).Click(); + WaitAssert.Equal("Event was handled", () => appElement.FindElement(By.Id("event-handled")).Text); + } + + [Fact] + public void PreventDefault_DotNotApplyByDefault() + { + var appElement = MountTestComponent(); + appElement.FindElement(By.Id("form-2-button")).Click(); + Assert.Contains("about:blank", Browser.Url); + } } } diff --git a/test/testapps/BasicTestApp/EventPreventDefaultComponent.cshtml b/test/testapps/BasicTestApp/EventPreventDefaultComponent.cshtml new file mode 100644 index 0000000000..3681b170f8 --- /dev/null +++ b/test/testapps/BasicTestApp/EventPreventDefaultComponent.cshtml @@ -0,0 +1,39 @@ +

Prevent default

+ +

+ Currently we don't call preventDefault by default on DOM events in most cases. + The one exception is for form submit events: in that case, if you have a C# onsubmit handler, + you almost certainly don't really want to perform a server-side post, especially given that + it would occur before an async event handler. +

+

+ Later, it's likely that we'll add a syntax for controlling whether any given event handler + triggers a synchronous preventDefault before the event handler runs. +

+ +

Form with onsubmit handler

+ +
{ })> + +
+ +

Form without onsubmit handler

+ +
+ +
+ +@if (didHandleEvent) +{ +

Event was handled

+} + +@functions { + bool didHandleEvent; + + async Task HandleClick() + { + await Task.Delay(250); // To give time for default action if it's going to occur + didHandleEvent = true; + } +} diff --git a/test/testapps/BasicTestApp/Index.cshtml b/test/testapps/BasicTestApp/Index.cshtml index ef1f56bddb..d43fe37668 100644 --- a/test/testapps/BasicTestApp/Index.cshtml +++ b/test/testapps/BasicTestApp/Index.cshtml @@ -34,6 +34,7 @@ +