skip to Main Content

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


  1. 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);
    
    Login or Signup to reply.
  2. 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

    Login or Signup to reply.
  3. 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>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search