Blazor Walkthrough: Act III - rochellew/csci_1260_spring2025 GitHub Wiki
🧙 "Peace and blessings upon you, traveler! You have already encountered my two brothers, which just leaves me, the
GREEN WIZARD. I have discovered a new plant, and would love to add it to the catalogue when you have completed it. I should probably avoid touching it for now, though...My brother the Red Wizard asked you to create a page for the creatures encountered by the Mysterious Traveler, and now I will task you with creating a page for the plant life.
This time, rather than simply listing out the items, we're going to create something called an image carousel which will automatically cycle through all of the plants you choose to include in the inaugural data set.
Best of luck!"
- In
/wwwroot/dataor/wwwroot(wherever you madecreatures.json), create a new file calledplants.json. - Create the JSON collection of plants, making sure you're following the attribute names and data types from the
Plantclass.
🧙 Wizard Wisdom: Remember, in order to create a collection of JSON objects, you need to encapsulate the objects (
{}) in brackets ([]) to indicate they are part of a collection and separate them by commas. Referencecreatures.jsonif you need a refresher.
- Populate this JSON file with enough appropriate keys and values for at least five plants.
Now that we have some plant data, let's update OrganismService.cs to be able to deserialize these plants into a List<Plant> and return it. We will create a structure called a circular queue in a few steps.
- Create a method called
GetPlantsFromJsonbased on the following criteria.- Has the
publicmodifier - Is marked as
async - Returns a
Task<List<Plant>> - Has no parameter variable definitions
- Has the
- Use the
GetCreaturesFromJsonmethod from the last tutorial as a template for the method body, but change creature to plant where needed.
- In
/Components/Pages, create a new.razorcomponent calledPlants.razor. - Paste the following code into
Plants.razorin order to create the new view.
@page "/plants"
@using TomeLibraryProject
@inject TomeBlazorProject.Services.OrganismService OrganismService
<h2>Magical Plants</h2>
@if (plants is null || plants.Count == 0)
{
<p>Loading plants...</p>
}
else
{
<div class="plant-carousel">
<img src="@CurrentPlant.ImageUrl" alt="@CurrentPlant.Name" />
<h3>@CurrentPlant.Name (@CurrentPlant.Rarity)</h3>
<p>@CurrentPlant.Description</p>
<p><strong>Bloom Season:</strong> @CurrentPlant.BloomSeason</p>
<p><strong>Medicinal:</strong> @(CurrentPlant.IsMedicinal ? "Yes" : "No")</p>
<p><strong>Poisonous:</strong> @(CurrentPlant.IsPoisonous ? "Yes" : "No")</p>
<div class="controls">
<button @onclick="RotateLeft">⟵ Previous</button>
<button @onclick="RotateRight">Next ⟶</button>
</div>
</div>
}
@code {
private Queue<Plant> plants = new();
private Plant CurrentPlant => plants.Peek();
private System.Timers.Timer? carouselTimer;
protected override async Task OnInitializedAsync()
{
var list = await OrganismService.GetPlantsFromJson();
if (list is not null)
{
foreach (var plant in list)
plants.Enqueue(plant);
StartTimer();
}
}
private void RotateRight()
{
if (plants.Count == 0) return;
var front = plants.Dequeue();
plants.Enqueue(front);
}
private void RotateLeft()
{
if (plants.Count == 0) return;
var tempList = plants.ToList();
var last = tempList[^1];
tempList.RemoveAt(tempList.Count - 1);
plants = new Queue<Plant>(new[] { last }.Concat(tempList));
}
private void StartTimer()
{
carouselTimer = new System.Timers.Timer(6000); // 6 seconds
carouselTimer.Elapsed += (_, _) =>
{
InvokeAsync(() =>
{
RotateRight();
StateHasChanged();
});
};
carouselTimer.AutoReset = true;
carouselTimer.Start();
}
public void Dispose()
{
carouselTimer?.Stop();
carouselTimer?.Dispose();
}
}- Take a few minutes to familiarize yourself with what the code is doing -- run the program and watch how the timer works with the carousel as well as the buttons to rotate left and right through the images.
You will likely note that things do not look particularly great at the moment, so let's add some CSS!
- Add the following CSS to
.app.css(do not replace anything, just add it to the end).
.plant-carousel {
text-align: center;
max-width: 600px;
margin: auto;
padding: 1rem;
background: #fefefe;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.plant-carousel img {
max-height: 200px;
border-radius: 12px;
margin-bottom: 1rem;
}
.controls {
margin-top: 1rem;
display: flex;
justify-content: center;
gap: 1rem;
}
.controls button {
padding: 0.5rem 1rem;
border: none;
background-color: #4b3f72;
color: white;
border-radius: 8px;
font-weight: bold;
cursor: pointer;
}
.controls button:hover {
background-color: #6c5ce7;
}
.controls {
margin-top: 1rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
}There are a few more things that will make this page really pop -- and you've got to figure them out on your own!
- Add some custom styling to indicate whether a given plant is poisonous or not (e.g., color the text next to "Poisonous" on the page a certain color whether the plant is or is not poisonous).
- Add some custom styling to indicate the rarity of the plant (e.g., the background color of the carousel
divcould change depending on the rarity of the given plant. - Add a feature to pause the timer so the images will pause their automatic rotation through the carousel.
These three features need to be present in order to receive credit for this portion of the tutorial.