moostang
moostang

Reputation: 93

Blazor: How to show one list item at a time

I am developing a blazor app which asks several questions to the user. I want to ask one question before proceeding to the next question. So, I have a list of questions, and I want to show each item from the list step-by-step instead of putting all the questions in a single view.

If I want to show all questions in a single page, then the following Index.razor will do. This is a working a code:

@foreach (var item in items)
{
   <h2>@item.Question</>
}


@code
{
    List<Item> items = new();

    protected override async Task OnInitializedAsync()
    {
        items = await HttpClient.GetFromJsonAsync<List<Item>>(NavigationManager.BaseUri + "items");
    }

}

where the Item class is:

public class Item
{ 
    public int Id { get; set; }
    public string Question { get; set; } 
}

BUT, I do not want that. I want to show one question at a time. Maybe something like this, i.e. where I can call some random question in a single view:

@* THIS CODE IS NOT WORKING *@

<h2>@items[3].Question</>


@code
{
    List<Item> items = new();

    protected override async Task OnInitializedAsync()
    {
        items = await HttpClient.GetFromJsonAsync<List<Item>>(NavigationManager.BaseUri + "items");
    }

}

I am guessing this has something to do with the await stuff, but cannot figure out at all.

Anyway, If I can get this right, then I can maybe continue writing code to call each item from the list one-by-one.

p.s For the rest of the code, I am just using the default Blazor template. The DbContext looks like this:

public class QuestionsContext: DbContext
{
    public DbSet<Item> Items { get; set; }

    public QuestionsContext(DbContextOptions options) : base(options) { }

}

and the controller looks like this:

[Route("items")]
[ApiController]
public class ItemController : Controller
{
    private readonly QuestionsContext _db;

    public ItemController(QuestionsContextdb)
    {
        _db = db;
    }

    [HttpGet]
    public async Task<ActionResult<List<Item>>> GetItems()
    {
        return await (_db.Items.ToListAsync());
    }
}

Upvotes: 0

Views: 512

Answers (1)

desmondische
desmondische

Reputation: 266

It is a bit hard to give a solution that would ideally fit your needs. For example, you haven’t really said how would you like the items to be changed — button click, timer or whatever.

Anyway, first of all, as already been mentioned you have to be sure your collection of items loaded by providing simple if-else statement.

Define some private fields to store data and use it for displaying.

Then, you can create a button (for sake of example) that will trigger the question update, and define a method that will be triggered.

@if (items is null)
{
  <p>Loading…</p
}
else 
{
  @_currentQuestion

  <button type=“button” @onclick=“UpdateCurrentQuestion”> Update Question </button>
}

@code {
  int _currentIndex = 0; // index to be incremented
  string? _currentQuestion; // displayed question

  List<Item> items = new();

  protected override async Task OnInitializedAsync()
  {
    items = await HttpClient.GetFromJsonAsync<List<Item>>(NavigationManager.BaseUri + "items");
    _currentQuestion = items[0].Question; // get the first question
  }

  void UpdateCurrentQuestion() 
  {
    _currentIndex++;
    _currentQuestion = items[_currentIndex].Question;      
  }
}

Unfortunately, I can’t test this right now, but it should do the trick.

Also, you can change the UpdateCurrentQuestion method to async Task and add a Task.Delay() if you don’t want a button.

I hope it helps!

Upvotes: 1

Related Questions