3

I use a Boolean property to disable a button after user clicking it, so that the click does not happen twice.

 private bool DisablePlaceOrderButton { get; set; } = false;
 private void PlaceOrder_Clicked()
    {
        DisablePlaceOrderButton = true;
        StateHasChanged();
        if (cart.Lines.Count() == 0)
        {
            DisablePlaceOrderButton = false;
            return;
        }
        ...
}

The button is designed as follows:

<button @onclick="@PlaceOrder_Clicked" disabled="@DisablePlaceOrderButton">Place Order</button>

But this is not working and button is disabled only after PlaceOrder method finishes executing. I have the same problem with an ajax indicator that after method execution, should be showed and after finishing should hide, Using an if block. In both cases statehaschanged has no effect. I use Blazor Server side preview 9. How to make these work?

mz1378
  • 1,415
  • 2
  • 15
  • 27
  • 4
    StateHasChanged informs the component that its state has changed but it does not render the component. The component will decide when to render itself. You can't do that in a synchronous method, you should async your code to let the component a chance to render. – agua from mars Jan 05 '20 at 10:31

1 Answers1

3

Please, read the comment made by agua from mars, and follow this code sample to see how it works... When you click on the button, the DisablePlaceOrder method is called, the title text changes to reflect the on-going action, during which the button is disabled. This occurs in the span of 3 seconds, including the re-rendering of the control to reflect the visual changes. Note that no call to StateHasChanged is made.

In real-life application, of course, you don't use the Task.Delay method, but you call method that do intensive work...

<button type="button" @onclick="@PlaceOrder_Clicked" disabled="@DisablePlaceOrderButton">@Title</button>

@code{
    private bool DisablePlaceOrderButton { get; set; } = false;

    public string Title { get; set; } = "Place Order";

    private async Task PlaceOrder_Clicked()
    {

        await DisablePlaceOrder();

        //if (cart.Lines.Count() == 0)
        //{
        DisablePlaceOrderButton = false;
        Title = "Place Order";
        // return;
        //}

    }

    async Task DisablePlaceOrder()
    {
        DisablePlaceOrderButton = true;
        Title = "Wait...";
        await Task.Delay(3000); 

    }
}
enet
  • 34,056
  • 4
  • 55
  • 89
  • 1
    The main part of your code is Task.Delay(), So I didn't create DisablePlaceOrder() method, and used the original PlaceOrder_Clicked() with the StateHasChanged() replaced with: await Task.Delay(1000); and every thing is fine. – mz1378 Jan 05 '20 at 13:06
  • 1
    But this is not right thing to do , right ? because statehaschagned() should re-render component. – Aarsh Mar 05 '20 at 04:38