This is a Blazor Server solution. The PopulateFilmography()
method sets a callback method in the FilmographyService
class and then calls filmographyService.GetFilmography
.
That service method gets data from an API and loops through the results. In each loop iteration, it calls the callback method. This method displays a modal (if not already open) and adds log entry to its data source. The idea is that the modal will display the activity of the API calls in real time.
The problem is that the modal only displays, with all the entries, after GetFilmography
is complete. I expected the line InvokeAsync(() => StateHasChanged());
to update the UI and display/update the modal, but that isn’t happening. I can see with breakpoints that the ShowLogEntry
callback is actually being called upon each iteration of the loop in the GetFilmography
. FilmographyService
is in a class library. It isn’t in the Blazor UI project.
I’ve tried these solution which don’t work:
- Making GetFilmography async and awaiting it
- Surrounding the
filmography = filmographyService.GetFilmography();
inawait Task.Run(()
- Also using
InvokeAsync
forlogEntries.Add(new LogEntry(narrative));
How to fix the modal not displaying/updating? I think I’m misunderstanding something about what is required for InvokeAsync(() => StateHasChanged());
to work.
@inject IModalService blazoredModalService;
@code {
private Filmography filmography;
private bool isModalOpen = false;
private List<LogEntry> logEntries = new List<LogEntry>();
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
PopulateFilmography();
}
}
private void PopulateFilmography()
{
filmography = new Filmography();
filmographyService.LogEntryCallback = new Action<String>(ShowLogEntry);
filmography = filmographyService.GetFilmography();
}
private void ShowLogEntry(String narrative)
{
if (!isModalOpen)
{
var modal = modalService.ShowModal<LogViewerModal>(new { LogEntries = logEntries });
isModalOpen = true;
}
logEntries.Add(new LogEntry(narrative));
InvokeAsync(() => StateHasChanged());
}
}
public class FilmographyService
{
public Action<String> LogEntryCallback { get; set; }
public Filmography GetFilmography(int personId, FilmographyRole role)
{
//Method contains other code that gets data from an API and returns filmography
foreach (TmdbBaseCredit credit in newCredits)
{
LogEntryCallback(credit.Title);
}
}
}