25

I'm using Grid.Blazor library to render server side grid on Blazor app. One of the column has a button with click event. So when button is clicked then grid row event is also fired along with button click event. I want to stop event propagation and only let button click event fired.

Grid:

  <GridComponent @ref="_gridComponent" T="QuickLists" Grid="@_grid"  OnRowClicked="@(async (item) => await ExerciseDetails(item))"></GridComponent>


Action<IGridColumnCollection<QuickExcerciseLists>> columns = c =>
        {
            c.Add().Titled("Actions").RenderComponentAs(typeof(ChildComponent)).SetWidth("5%");
            c.Add(o => o.Name, comparer).Titled("Name").SetWidth("10%");
            c.Add(o => o.Age, comparer).Titled("Age").SetWidth("15%");
            c.Add(o => o.Address, comparer).Titled("Address").RenderComponentAs<MatTooltip>().SetWidth("15%");
        };

Custom Column Component :

<MatBlazor.MatButton Icon="@MatIconNames.Remove_red_eye" @onclick="@ShowData" @onclick:stopPropagation="true"></MatBlazor.MatButton>

I tried passing @onclick:stopPropagation in the child button component. But it's given below compile error.

The component parameter 'onclick' is used two or more times for this component. Parameters must be unique (case-insensitive). The component parameter 'onclick' is generated by the '@onclick:stopPropagation' directive attribute.

I'm running .Net core 3.1.201. Any help is highly appreciated.

Vencovsky
  • 28,550
  • 17
  • 109
  • 176
Venkata Dorisala
  • 4,783
  • 7
  • 49
  • 90
  • 2
    This @onclick:stopPropagation="true" should be fine. You are not using the onclick directive twice. Can't say what is the source of the error... – enet May 03 '20 at 19:00
  • yea. the error says '@onclick:stopPropagation' generates `onclick`. So it makes 2 `onclick` events on the control. – Venkata Dorisala May 03 '20 at 19:21
  • 2
    `MatButton` is not a button, is a component, contains several elements. Maybe `MatButton` doesn't support `StopPropagation`. Check code on GitHub, is an open project. – dani herrera May 03 '20 at 20:52
  • @daniherrera Yes. You are right. It's working with regular html elements but not with custom elements. Thanks. – Venkata Dorisala May 04 '20 at 12:40

5 Answers5

27

In case it helps, and to add to the comment @Ivan made for the MatBlazor MatButton/MatIconButton which didn't seem to work for me, I used the following workaround:

<div @onclick:stopPropagation="true" @onclick:preventDefault="true">
  <MatButton OnClick="@DoSomething" @ref="MyButton">Do it!</MatButton>
</div>

I needed to use both stopPropagation and preventDefault. I had to use the div wrapper as MatButton didn't allow me to add multiple onclicks.

pfeds
  • 2,183
  • 4
  • 32
  • 48
5

I was having a similar issue with an expander. I wanted to be able to click a button inside an expander row without having the row expand. I was able to accomplish this by using @onmousedown for my C# code and onclick for the window event call

 <a class="text-primary" @onmousedown="() => MyModal.Open()" onclick="event.stopPropagation()"> Button </a>
JP Garza
  • 212
  • 3
  • 16
1

For those trying to stop scroll propagation

Here's what didn't work for me
(any for itself and all together)

@onmousewheel:stopPropagation
@onmousewheel:preventDefault
@onwheel:stopPropagation
@onwheel:preventDefault
@onscroll:stopPropagation
@onscroll:preventDefault

Here are two links that describe this bug on github

Blazor preventDefault with wheel event

Blazor webassembly: @onwheel:preventDefault has no effect

These issues are being postponed since November 2019.

In short, and I'll quote some comments from these links

Use of preventDefault within scroll-type events (including wheel) is discouraged by browsers because it reduces the responsiveness of the site.

The recommended alternative is to block default scrolling behaviors using the CSS style touch-action: none

Simple and short workaround

This is suggested by sergey-su from the second link I shared.

site.js :

window.myUtils = {
    addDefaultPreventingHandler: function (element, eventName) {
        element.addEventListener(eventName, e => e.preventDefault(), { passive: false });
    }
};

your razor component :

<div @ref=myElementReference>...</div>

@code{
    
    ElementReference? myElementReference = default!;
    
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
            await jsRuntime.InvokeVoidAsync("myUtils.addDefaultPreventingHandler", myElementReference, "wheel");
    }
}

Possibly blazor does not set the passive option correctly when it adds its event listener. It should disable the scroll optimization by setting passive: false when @on:preventDefault is present for a scrolling event in the razor markup.

Conclusion

When going with this route you don't need the @on___:stopPropagation or @on___:preventDefault that I mentioned at the top.

The @onmousewheel and @onwheel still work just fine.

Go like sergey-su's bug report and workaround if you find this helpful.

Monset
  • 648
  • 5
  • 25
0

I was having the exact same issue with a Table. It seems that now MatBlazor buttons have a way to stop propagation: OnClickStopPropagation="true"

Following code works for me, with MatIconButton and MatButton:

<MatBlazor.MatButton Icon="@MatIconNames.Remove_red_eye" OnClick="@ShowData" OnClickStopPropagation="true"></MatBlazor.MatButton>
Ivan
  • 51
  • 1
  • 6
0

I faced different issue with multiple handlers. Because I was using @onclick and @onshortclick like this:

<div @onclick="ParentClick" style="width:500px;height:300px">

    <h1>parent click</h1>

    <h1 @onshortclick="ChildClick">child with propagation</h1>

    <h1 @onshortclick="ChildClick" 
        @onclick:stopPropagation="true" 
        @onshortclick:stopPropagation="true">child without click</h1>
</div>

As you can see the parent has @onclick and children have @onshortclick. An in order not to propagate the event up to the parent, you have to stopPropagate for both events.

Kebechet
  • 1,461
  • 15
  • 31