dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.

Home Page:https://asp.net

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Blazor custom events incorrect currentTarget

Timonney opened this issue · comments

Hi,

I want to have a custom event for click that give the position relative to the element that catches the event.

For that, I created a custom event for onclick

    Blazor.registerCustomEventType('clickrelative', {
      browserEventName: 'click',
      createEventArgs: event => {
        console.log(event.currentTarget);
        const bb = event.currentTarget.getBoundingClientRect();
        return {
          relativePositionX: event.pageX - bb.x,
          relativePositionY: event.pageY - bb.y
        };
      }
    });

I applied the event to a div element
<div unselectable="on" @onclickrelative="OnClickRelative" class="timeline" >

And the issue is that the currentTarget properties return the document instead of the div. And I can't use target or path[0] because the event might be called by some children of the div.

I could solve the issue by adding a specific property to my div of find it in the path but it would be nicer if the currentTarget would work

Hm the events args are created once, so I guess it wouldn't be enough to provide the candidateElement in createEventArgs, since there could be multiple listeners for the same event in the hierarchy/path? But maybe it is better than nothing?

const candidateElement = candidateEventTarget as Element;
const handlerInfos = this.getEventHandlerInfosForElement(candidateElement, false);
if (handlerInfos) {
const handlerInfo = handlerInfos.getHandler(eventName);
if (handlerInfo && !eventIsDisabledOnElement(candidateElement, browserEvent.type)) {
// We are going to raise an event for this element, so prepare info needed by the .NET code
if (!eventArgsIsPopulated) {
const eventOptionsIfRegistered = getEventTypeOptions(eventName);
// For back-compat, if there's no registered createEventArgs, we supply empty event args (not null).
// But if there is a registered createEventArgs, it can supply anything (including null).
eventArgs = eventOptionsIfRegistered?.createEventArgs
? eventOptionsIfRegistered.createEventArgs(browserEvent)
: {};
eventArgsIsPopulated = true;
}

@Timonney thanks for contacting us.

Blazor uses event delegation and sets up the handler at the document level. I believe you can use target to get to the original element.

@javiercn the target properties give the correct value but that's not what I want.

The target give the element that first trigger the event, which can be a child of the element that have the handler.

<div class="timeline-body"> <!-- onclickrelative is here  -->
	<div class="timeline-body-scene">
		<div class="timeline-body-scene-buffered" />
		<div class="timeline-body-scene-past">
			<div class="timeline-body-handle" />
		</div>
	</div>
</div>

For this hierarchy, if I click the "timeline-body-handle" div, the target will be the "timeline-body-handle" and the currentTarget should be the "timeline-body", which is not the case. And I need to have "timeline-body" for my calculation.

@Timonney You can use Event.composedPath() to get to it. See https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath for details.

As I mentioned, this is by design since blazor uses event delegation to save memory.

@javiercn It's possible to use composedPath but it required to implement a way to identify the correct element in the path and it forces to have only one event of the kind in the given path as it would be hard (impossible?) to identify the correct one.

I don't think it will be an issue in my case but it can become one on other cases.

I will probably implement the composedPath solution but it would be nice to have a better alternativ that can give the target

@Timonney I expect you're already thinking of the following kind of workaround, but just for anyone else reading I'll write it out.

You could add some sort of identifying feature to the elements that will raise these special events, for example a CSS class or a custom HTML attribute, and then use that to determine which element in the path is the one you want.

I know that's not as convenient as having the framework tell you which element(s) have registered a corresponding handler, but at least it's something you can do immediately without needing a new framework feature.

Thank you for contacting us. Due to a lack of activity on this discussion issue we're closing it in an effort to keep our backlog clean. If you believe there is a concern related to the ASP.NET Core framework, which hasn't been addressed yet, please file a new issue.

This issue will be locked after 30 more days of inactivity. If you still wish to discuss this subject after then, please create a new issue!