Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,56 @@ private static bool TryGetParentFormElementSpecialCase(
IHtmlButtonElement { Type: "submit", Form: not null } button => button.Form,
_ => null
};

// If form is still null, try to find it by the form attribute for submit buttons/inputs
if (form is null && element.HasAttribute("form"))
{
var isSubmitElement = element switch
{
IHtmlInputElement { Type: "submit" } => true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the HTML standard allow for an tag to be used in this scenario? If so, also add a test case for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the HTML5 standard allows <input type="submit"> with the form attribute. Added test cases in commit 36a5d18 for both button and input elements outside forms using the form attribute.

IHtmlButtonElement { Type: "submit" } => true,
_ => false
};

if (isSubmitElement)
{
var formId = element.GetAttribute("form");
if (!string.IsNullOrEmpty(formId))
{
// Try to find the form element by traversing up to find a common ancestor
// and then searching down for the form
form = FindFormById(element, formId);
}
}
}

return form is not null
&& form.TryGetEventId(Htmlizer.ToBlazorAttribute("onsubmit"), out eventId);
}

private static IHtmlFormElement? FindFormById(IElement element, string formId)
{
// Traverse up the DOM tree to find a common ancestor and search its children
// for the form with the matching ID. This handles cases where the button and
// form are siblings or in different subtrees.
var current = element.Parent as IElement;
while (current is not null)
{
// Search children of current element for the form with matching ID
foreach (var child in current.Children)
{
if ((child.Id == formId || child.GetAttribute("id") == formId) && child is IHtmlFormElement htmlForm)
{
return htmlForm;
}
}

// Move up to parent to widen the search
current = current.Parent as IElement;
}

return null;
}

private static bool EventIsDisabled(this IElement element, string eventName)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<form @onsubmit="Callback" id="form1">
</form>
<button type="submit" form="form1" id="submit-button">Submit Button</button>
<input type="submit" form="form1" id="submit-input" value="Submit Input" />

@code {
public bool SubmitWasCalled { get; private set; }

private void Callback()
{
SubmitWasCalled = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,24 @@ public void ClickingOnSubmitButtonOutsideTriggersOnsubmitOfForm()

cut.Instance.SubmitWasCalled.ShouldBeTrue();
}

[Fact]
public void ClickingOnSubmitButtonOutsideWithFormAttributeTriggersOnsubmit()
{
var cut = Render<FormWithSubmitElementsOutside>();

cut.Find("#submit-button").Click();

cut.Instance.SubmitWasCalled.ShouldBeTrue();
}

[Fact]
public void ClickingOnSubmitInputOutsideWithFormAttributeTriggersOnsubmit()
{
var cut = Render<FormWithSubmitElementsOutside>();

cut.Find("#submit-input").Click();

cut.Instance.SubmitWasCalled.ShouldBeTrue();
}
}
Loading