dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.5k stars 10.04k forks source link

Blazor event bubbling and eventtarget (client side) #11681

Closed LaughingJohn closed 4 years ago

LaughingJohn commented 5 years ago

I think this is related to #5545 and also https://github.com/aspnet/Blazor/issues/1277

Basically I'm trying to implement a "modal" dialog similar to this example: https://www.w3schools.com/howto/howto_css_modals.asp

I want the dialog to close when the close button is clicked or when the overlay is clicked. In other words if the user clicks outside the dialog. I want them to be able to click inside the dialog so they can copy/paste if necessary.

My code looks like this:

<!-- The Modal -->
<div id="fmmodal-dialog" class="fmmodal" style="display: @(IsOpen ? "block" : "none");" onclick="@CloseDialogAsync">
    <!-- Modal content -->
    <div class="fmmodal-content">
        <div class="fmmodal-header">
            <div class="fmmodal-close" onclick="@CloseDialogAsync">&times;</div>
            @HeaderContent
        </div>
        <div class="fmmodal-body">
            @BodyContent
        </div>
    </div>
</div>

If the user clicks anywhere it closes. If I remove the onclick event from the fmmodal-dialog div then only the close button closes the dialog.

I tried adding onclick="onclick="event.stopPropagation();" to the fmmodeal-content which stopped click events bubbling up but then the close button doesn't work and I'm not quite sure why.

<!-- The Modal -->
<div id="fmmodal-dialog" class="fmmodal" style="display: @(IsOpen ? "block" : "none");" onclick="@CloseDialogAsync">

    <!-- Modal content -->
    <div class="fmmodal-content" onclick="event.stopPropagation();" >
        <div class="fmmodal-header" onclick="">
            <div class="fmmodal-close" onclick="@CloseDialogAsync">&times;</div>
            @HeaderContent
        </div>
        <div class="fmmodal-body">
            @BodyContent
        </div>
    </div>
</div>

The example uses event.target to test if they user is clicking on the overlay, but I can't see a way of getting event.target in Blazor?

// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
  if (event.target == modal) {
    modal.style.display = "none";
  }
}

Apologies if this isn't the right place to post this - is there a forum somewhere that would be better suited?

The whole component is attached. FmModalDialog.zip

LaughingJohn commented 5 years ago

One point of note is that I need to be able to open/close the dialog from a parent dialog so I currently have an "IsOpen" boolean in the C# code.

I tried just using Javascript to do the open/close but I'm struggling to figure out how to keep it in sync. To use javascript I have to use the onclick event in order to get the event.target. Unless I'm missing something I can't then call back into the instance method to keep the bool in sync?

mkArtakMSFT commented 5 years ago

Thanks for contacting us, @LaughingJohn. The actual ask you have here is indeed a duplicate with the referenced issues. As for the rest leaving this issue open so community members can help you out.

sbuchok commented 5 years ago

You actually don't need to set the style at all.

` @if(IsOpen) { <div id="fmmodal-dialog" class="fmmodal" @onclick="@CloseDialogAsync">

<!-- Modal content -->
<div class="fmmodal-content" onclick="event.stopPropagation();" >
    <div class="fmmodal-header" onclick="">
        <div class="fmmodal-close" @onclick="@CloseDialogAsync">&times;</div>
        @HeaderContent
    </div>
    <div class="fmmodal-body">
        @BodyContent
    </div>
</div>

}`

You can wrap the component in an "if" statement. Then you just need to set IsOpen to true or false in order to show and hide it. I made a modal dialog for myself and this is how I ended up doing it. Don't forget that your events need to start with @ "@onclick=@CloseDialogAsync" (at least in latest version).

If you need more help, let me know and I'll see about posting an example to https://blazorfiddle.com/

Hope this helps.

LaughingJohn commented 5 years ago

dialog Thanks @sbuchok that worked fine as far as showing/hiding is concerned but I still couldn't get it so that the dialog would close when the close "button" is pressed or when the overlay is clicked (see attached image). Your example seems to have lost the overlay part. I can get it to close only when the close "button" is clicked or alternatively when you click anywhere inside or outside the fmmodel-content bit. I want it to work for the button or overlay, but not content. Adding event.stopPropagation(); just seems stop any click working! :(

sbuchok commented 5 years ago

@LaughingJohn did you add a click event to the overlay? If you add the same event to the overlay that you did for the "X" icon, I believe it should work.

Sorry for the late reply

ghost commented 4 years ago

Thank you for contacting us. Due to no activity on this 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.