Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When interacting with a child component's html, should it be treated in the whole rendered context? #983

Open
JelleHissink opened this issue Feb 17, 2023 · 6 comments

Comments

@JelleHissink
Copy link
Contributor

I noticed something.
When I have a form and a component containing a submit button....

  • When I render the outer component, find the html button and click, the submit is fired.
  • When I render the outer component, locate the inner component and fire the button, click, the click is only bubbled within it's own rendered html of the sub-component, hence no submit is ever triggered.

Is this by design? Or is it easy to implement, or consider for V2

@linkdotnet
Copy link
Sponsor Collaborator

Thanks for the issue. I will have a look into it.

@linkdotnet
Copy link
Sponsor Collaborator

Root Cause Analysis

I took the time to look into what is the problem here. First let's consider those two components:

Parent:

<form id="my-form" @onsubmit="() => FormSubmitted = true">
	<InnerSubmitForm></InnerSubmitForm>
</form>

And InnerSubmitForm:

<button id="inside-form-button" type="submit" @onclick="...">Submit</button>

The following test will work:

var cut = RenderComponent<OuterSubmitForm>();

cut.Find("button").Click();

cut.Instance.FormSubmitted.ShouldBeTrue();

This one will fail:

var cut = RenderComponent<OuterSubmitForm>();

cut.FindComponent<InnerSubmitForm>().Find("button").Click();

cut.Instance.FormSubmitted.ShouldBeTrue();

The reason lays inside FindComponent:
The TestRenderer.GetOrCreateRenderedComponent method does the following (line 308):

else
{
	LoadRenderTreeFrames(componentId, framesCollection);
	result = activator.CreateRenderedComponent(componentId, component, framesCollection);
	renderedComponents.Add(result.ComponentId, result);
}

Basically we are creating more or less a new component that is disconnected from its past parent. So when inspecting the nodes we will see that our parent node is of type HtmlBodyElement instead of HtmlFormElement. That also means that in TriggerEventDispatchExtensions:GetDispatchEventTasks the following line will return only the button and the body element:

foreach (var candidate in element.GetParentsAndSelf())

@egil
Copy link
Member

egil commented Feb 19, 2023

@linkdotnet, thanks for investigating. I am not sure the conclusion is exactly correct though. The problem should not be related to the code you quote from TestRenderer, the initial call to RenderComponent will make sure the entire component tree is rendered at that point.

However, when we issue a FindComponent we are creating a new RenderedComponent<InnerSubmitForm>, whose Markup property will be empty and thus regenerated from the point of view of the InnerSubmitForm, which does not include the part of the parent's components HTML, cut.Markup. So the component tree is intact, but the markup is separate.

There is no straightforward fix for this.

  1. The efforts around creating an AngleSharpRenderer would be one approach to solving it.
  2. A custom tree-based string structure used to represent cut.Markup could also be a possibility, where each leaf in the tree represents the markup produced by a component. That would enable us similarly track which part of the AngleSharp DOM tree belongs to which component and keep one source of truth and a single share DOM/Markup for the entire component tree.

Either way its not an easy thing to do, and probably not something that we can jump into immediately.

@JelleHissink
Copy link
Contributor Author

I understand, it is just a strange thing a colleague of mine ran into and he struggled with it for a while. Then I started to help, look at the code and it made sense, but from his test code it was not immediately obvious what was happening as one button click would work, and the other button would not. (The latter being a submit button)

@egil
Copy link
Member

egil commented Feb 19, 2023

@JelleHissink, no it's an unfortunate and annoying limitation we currently have.

@egil
Copy link
Member

egil commented Feb 23, 2023

This is another issue that would be solved by #48.

@egil egil modified the milestone: 2.0.0 May 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants