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

Ensure DOM event handlers are triggered like Blazor does it #518

Closed
egil opened this issue Oct 17, 2021 · 3 comments
Closed

Ensure DOM event handlers are triggered like Blazor does it #518

egil opened this issue Oct 17, 2021 · 3 comments
Assignees
Labels
bug Something isn't working investigate This issue require further investigation before closing.

Comments

@egil
Copy link
Member

egil commented Oct 17, 2021

bUnit currently triggers DOM event handlers like this:

  • For bubbling events, e.g. @onclick events, it starts with the trigger element and invokes the Blazor event handler (if present), and then walking up the DOM tree and finding all parent elements with a Blazor event handler attached matching the triggered event type, and triggers those as they are found. If a "stop event propagation" or disabled event is found, the bubbling stops.
  • For non-bubbling events, the Blazor event handler bound to the triggering element is invoked.
  • In both cases, if no Blazor event handler is found, a MissingEventHandlerException is thrown. For bubbling events, at least one Blazor event handler must be found in the DOM tree.
  • If an Blazor event handler is triggered after it has been removed/disposed, i.e. because the owning component has been disposed/removed from the render tree, an exception is thrown by the Blazor Renderer (a There is no event handler associated with this event. EventId XX exception).

This works well, and should align with how Blazor does it. However, it is unclear what Blazor does in the following scenario (inspired by #517):

Suppose we have (maybe multiple) components that render out something like the following markup:

<tr onclick="...">
  <td onclick="...">
    <button onclick="...">

The user triggers the event handler bound to the button element, which causes the DOM to be updated, such that the td elements onclick handler is removed.

  1. Does Blazor still trigger the td and tr onclick event handlers?
  2. Does Blazor only trigger the tr onclick event handler that is still bound?
  3. or does the bubbling stop, i.e. no more event handlers are triggered?

My experiments up till now has been inconclusive, so hoping somebody, perhaps @SteveSandersonMS, can help clear things up.

@egil egil added the enhancement New feature or request label Oct 17, 2021
@egil
Copy link
Member Author

egil commented Oct 17, 2021

My current plan is the following:

  1. If the target element's event handler throws or had been disposed, then the exception will get thrown to the user.
  2. If a bubbled event handlers throw, then those exception are passed to the user. If a bubbled events handlers have been disposed, the exception from the Blazor renderer is swallowed/ignored.
  3. If the a bubbled event handler has been disposed, any parent bubbling events are skipped, even if they are still there.

@egil egil added bug Something isn't working investigate This issue require further investigation before closing. and removed enhancement New feature or request labels Oct 17, 2021
@egil egil self-assigned this Oct 20, 2021
@egil
Copy link
Member Author

egil commented Oct 20, 2021

Another reason to follow the plan mentioned above is that this will restore the functionality of from before the 1.2.49 release which effectively swallowed all exceptions in most cases. So this is the path of "least surprise" for the users.

@egil
Copy link
Member Author

egil commented Oct 20, 2021

Actually, bUnit pre 1.2.49 did trigger the top parent element event handler, even if a lower event handler was disposed. It seems, based on experimenting with Blazor Server, that it is actually able invoke all event handlers before they get disposed. I.e. this component sets all three properties to true when the button is clicked:

<div @onclick="() => TopDivClicked = true">
@if (!BtnClicked)
{
	<div @onclick="() => MiddleDivClicked = true">
		<button @onclick="() => BtnClicked = true">Click me!</button>
	</div>
}
</div>

<p>@BtnClicked</p>
<p>@MiddleDivClicked</p>
<p>@TopDivClicked</p>

@code {
	public bool BtnClicked { get; private set; } = false;
	public bool MiddleDivClicked { get; private set; } = false;
	public bool TopDivClicked { get; private set; } = false;
}

Currently I cannot come up with a way to do the same in bUnit. The best we can do is to ignore then missing event handler for the MiddleDivClicked event and continue with the TopDivClicked event handler.

@egil egil closed this as completed in e5bab37 Oct 20, 2021
egil added a commit that referenced this issue Oct 20, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working investigate This issue require further investigation before closing.
Projects
None yet
Development

No branches or pull requests

1 participant