New to Blazor and I am migrating an old site to help learn.
This is a classic list all items, click Item to view details scenario
I have done the list all items in 1 page "Portfolio" using the following (which works perfect)
@code {
private artWork[]? artWorks;
protected override async Task OnInitializedAsync()
{
artWorks = await Http.GetFromJsonAsync<artWork[]>("data/artwork.json");
}
public class artWork
{
public int artworkID { get; set; }
public string? artworkName { get; set; }
public string? artworkFilename { get; set; }
public string? description { get; set; }
public string? artworkMediumID { get; set; }
public string? price { get; set; }
public string? width { get; set; }
public string? height { get; set; }
}
}
and I have a for each like so
@foreach (var artWork in artWorks)
{
<div class="art-wrapper">
<div class="img-thumb">
<a href="img/artwork/@artWork.artworkFilename" ToolTip="@artWork.artworkName - By Trevor Bollen" title="@artWork.artworkName - By Trevor Bollen">
<img src="img/artwork/@artWork.artworkFilename.Replace(".jpg", "_thumb.jpg")" title="@artWork.artworkName - By Trevor Bollen" alt="@artWork.artworkName - By Trevor Bollen" />
</a>
</div>
<div class="art-info">
<h3>@artWork.artworkName</h3>
<p><b>Medium:</b> @artWork.artworkMediumID </p>
<p><b>Size:</b> @artWork.width x @artWork.height (cm) </p>
<p><b>Price:</b> £@artWork.price</p>
<p><a href="portfoliodetail/@artWork.artworkID"><img src="img/btn-detail-sml.jpg" Class="btnViewDetail" AlternateText="Click here to view artwork details" ToolTip="Click here to view artwork details" /></a></p>
</div>
</div>
}
Which links through to the portfoliodetail page with Parameter. My question is, on this page how do I get the single record from my JSON using the ID passed through? So far I have the following but not sure how to filter or get by ID
@code {
private artWork? artWorks;
protected override async Task OnInitializedAsync()
{
artWorks = await Http.GetFromJsonAsync<artWork>("data/artwork.json");
}
public class artWork
{
public int artworkID { get; set; }
public string? artworkName { get; set; }
public string? artworkFilename { get; set; }
public string? description { get; set; }
public string? artworkMediumID { get; set; }
public string? price { get; set; }
public string? width { get; set; }
public string? height { get; set; }
}
}
Sample of Data shown below.
Here's a fairly simple example using a service to get and cache the Json data and provide methods to get a collection or a single object.
This example is based on getting this simple record:
public record CountryRecord(string Country, string Continent);
A Repository Service to get and cache the data:
public class CountryRepository
{
private readonly IHttpClientFactory _httpClientFactory;
private List<CountryRecord> _countries = new();
private Task? _getDataTask;
private object _lock = new();
public CountryRepository(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async ValueTask<IEnumerable<CountryRecord>> GetItemsAsync()
{
await GetData();
return _countries;
}
public async ValueTask<CountryRecord?> GetItemAsync(string country)
{
await GetData();
return _countries.FirstOrDefault(item => item.Country.Equals(country));
}
private Task GetData()
{
if (_getDataTask is not null)
return _getDataTask;
// ensures only one process can start the Task
lock (_lock)
{
if (_getDataTask is null)
_getDataTask = this.GetHttpDataAsync();
}
return _getDataTask;
}
private async Task GetHttpDataAsync()
{
var httpClient = _httpClientFactory.CreateClient();
var countries = await httpClient.GetFromJsonAsync<List<CountryRecord>>("https://localhost:7191/sample-data/countries.json");
ArgumentNullException.ThrowIfNull(countries, "Json file not found.");
_countries = countries;
}
}
And the registered service:
builder.Services.AddHttpClient();
builder.Services.AddSingleton<CountryRepository>();
You can now inject the service into any page/component and either get the full collection by calling GetItemsAsync
or a single item by calling GetItemAsync
.