Search code examples
razorlambdaasync-awaitdelegatesblazor

Call async method in blazor in html attribute


I'm trying to call an async function to retrieve data from an input and pass it to either the src or style attribute of an element depending on what it is. However, when I try to await it I get an error of:

The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'

  <div class="swiper-slide" style="
        background-image: url(@await LinkConverter.GetLinkFromData(media)">
  </div>

But when I try to use a lambda expression like:

  <div class="swiper-slide">
         <video src="@async () => await LinkConverter.GetLinkFromData(media, true)" width="320" height="240">
         </video>
  </div>

I get the following error(which I don't understand):

Cannot convert lambda expression to type 'object' because it is not a delegate type

The function is inside of a foreach and some if statements so I would much rather not have to do something where I create a list of the results at OnIntializedAsync and end up duplicating my code.


Solution

  • I would recommend using a component for this.

    Your foreach might be something like this

    @foreach(var media in MediaItems)
    {
      <DisplayMedia @key=media FetchMediaTask=@(()=>LinkConverter.GetLinkFromData(media)) />
    }
    

    And DisplayMedia would be

    @typeparam T
    <div class="swiper-slide" style="
          background-image: url(@Data)">
    </div>
    @code
    {
     [Parameter] public Func<Task<T>> FetchMediaTask { get; set; }
     T Data;
     protected override async Task OnAfterRenderAsync(bool first)
     {
      if (first)
      {
       Data = (T)await FetchMediaTask();
       StateHasChanged();
      }
     }
    }
    

    In this way, you can render the divs and await the GetLinkFromData inside the Component, which is supported.

    Demo: https://blazorrepl.com/repl/GEbcFnEm587VpE6g22