How to Invoke Js file once data is loaded in Blazor

Viewed 69

Am calling api to load data under async Task OnAfterRenderAsync(bool firstRender) But jscript is loaded before users gets loaded in UI

How can i calling js once data is loaded in Users list?

Code behind

protected override async Task OnAfterRenderAsync(bool firstRender)
{
   List<User> users = await Getuser(Request);
   await jsRuntime.InvokeAsync<IJSObjectReference>("import", "/js/scripts/test.js");
}

UI

  <div class="user-list">
    <ul>
      @foreach (var user in users)
       {
         <li>
          <h5 class="mb-25">@user.name</h5>                               
         </li>
       }
    </ul>
  <div>
3 Answers

In OnAfterRenderAsync() method, you are load user data (from API) to local variable. Your foreach loop works on another list declared in the component.

Use:

users = await Getuser(Request);

instead of:

List<User> users = await Getuser(Request);

Use OnInitializedAsync to retrieve data and OnAfterRenderAsync for js interop.

In test.js you have to export the function that adds the click events:

export function addClickEvents() {
    // add your js code here
    if ($('.user-list').find('li').length) { $('.user-list').find('li').on('click', function (e) { $('.details').toggleClass('show'); }); }
}

Then after importing the js module you have to invoke this function:

private List<User> users;

protected override async Task OnInitializedAsync()
{
    users = await Getuser(Request);
}

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        var module = await jsRuntime.InvokeAsync<IJSObjectReference>("import", "/js/scripts/test.js");
        
        // invoke addClickEvents function
        await module.InvokeVoidAsync("addClickEvents");
    }
}

Also in UI you should check if list is null.

@if (users != null)
{
  <div class="user-list">
    <ul>
      @foreach (var user in users)
      {
        <li>
          <h5 class="mb-25">@user.name</h5>                               
        </li>
      }
    </ul>
  <div>
}
else
{
  <p>Loading...</p>
}

Blazor component lifecycle

I think you want to render the users to UI before importing the js file, if that is what you want, you need to force component to apply changes to users list after you get them by using StateHasChanged() :

Code behind:

private List<User> users;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
   users = await Getuser(Request);
   StateHasChanged(); // you need to use StateHasChanged to apply changes
   //await Task.Delay(0); // this will give the main thread a chance to apply changes but as the below call is also async operation, you might not need to delay to apply changes
   //So first try without delay, if it is not worked try with delay
   await jsRuntime.InvokeAsync<IJSObjectReference>("import", "/js/scripts/test.js");
}

UI:

<div class="user-list">
    <ul>
      @foreach (var user in users ?? Enumerable.Empty<User>()) @*supply empty Enumerable if list is null*@
       {
         <li>
          <h5 class="mb-25">@user.name</h5>                               
         </li>
       }
    </ul>
  <div>
Related