Search code examples
async-awaitblazorblazor-client-sidematblazor

Calling an async function from a sync function


I am building a Blazor client side application. I am using MatBlazor components.

I have two MatSelectString controls on a page. The first one is used to select a category, and the second one to select products from the category. So I have it setu up like so:

<MatSelect Outlined="true" Label="Category" @bind-Value="@Category">
    <MatOptionString></MatOptionString>
    @foreach (var cat in GetCategories())
    {
        <MatOptionString Value="@cat">@cat</MatOptionString>
    }
</MatSelect>
<MatSelect Outlined="true" Disabled="@(!string.IsNullOrWhiteSpace(Category))" Label="Product" @bind-Value="@Product" >
    <MatOptionString></MatOptionString>
    @foreach (var prod in GetProducts(Category))
    {
        <MatOptionString Value="@prod">@prod</MatOptionString>
    }
</MatSelect>

Within the GetProducts(Category) code, I want to call the backend. The issue is that there is only a HttpClient.GetJsonAsync<>() method, that cannot be called from within a non-async method. But GetProduct() cannot be made async.

Things I have tried:

  • Putting the call to my function inside an async lambda (not allowed in foreach or in other code blocks)
  • Using Task.Result (it hangs)
  • Putting the back-end call in other component level async events (gets called multiple times)

Any ideas?


Solution

  • You can use ValueChanged EventCallback:

    <MatSelect 
        Outlined="true" 
        Label="Category" 
        ValueChanged="(string i)=>OnChangeCategory(i)"> @* <-- here *@
        <MatOptionString></MatOptionString>
        @foreach (var cat in GetCategories())
        {
            <MatOptionString Value="@cat">@cat</MatOptionString>
        }
    </MatSelect>
    
    @code
    {
       protected async Task OnChangeCategory(string newValue)
       {
          this.Category = newValue;
          // call backend async tasks
          // ...
       }
    

    Check it out at blazorfiddle.com