I haven't done any web/frontend development in a while, and so I'm a bit rusty. I'm using ASP.NET Core 5 with Razor Pages.
I'm trying to create an edit page that would allow me to edit the children (1:n) of a given entity. For now, I have a country/city sample - list of countries, each with a few cities. What I want to do is show all the countries (works fine), and then pick a country and edit its cities. That's where I'm struggling.
These are my model classes:
public class Country
{
public string IsoCode { get; set; }
public string Name { get; set; }
// more properties in the future
public ICollection<City> Cities { get; set; }
}
public class City
{
public string Name { get; set; }
public int Population { get; set; }
public Country Country { get; set; }
[ForeignKey("Country")]
public string CountryIsoCode { get; set; }
// more properties to come
}
The Razor page I have to show and edit the cities for a given country looks something like this:
View:
@page "{isocode}"
@using CountryCityDemo.Models
@model CountryCityDemo.Pages.EditCitiesModel
<h3>Edit cities for a country</h3>
<div class="container">
<form method="post">
<div class="row mb-1">
<div class="col-md-5 font-weight-bold">
<label class="control-label">@Model.SelectedCountry.Name</label>
</div>
</div>
@foreach (City city in Model.SelectedCountry.Cities)
{
<div class="row mb-1">
<div class="col-md-3 font-weight-bold">
<label class="control-label">Name of the city</label>
</div>
<div class="col-md-5 font-weight-bold">
<input asp-for="@city.Name" class="form-control" />
</div>
</div>
<div class="row mb-1">
<div class="col-md-3">
<label class="control-label">Population</label>
</div>
<div class="col-md-2">
<input asp-for="@city.Population" class="form-control" />
</div>
</div>
}
<input type="submit" value="Update" />
</form>
</div>
Page model class:
public class EditCitiesModel : PageModel
{
[BindProperty]
public Country SelectedCountry { get; set; }
public async Task OnGetAsync(string isocode)
{
// get countries from provider - including their cities
SelectedCountry = CountryProvider.GetCountry(isocode, true);
}
public async Task<IActionResult> OnPostAsync(string isocode)
{
// fetch the list of cities for this country
List<City> citiesForCountry = CityProvider.GetCitiesForCountry(isocode).ToList();
// update those cities
if (await TryUpdateModelAsync<List<City>>(citiesForCountry, "city"))
{
// save the updated cities
}
/* I also tried to use the "SelectedCountry" bind property - but had the same results:
SelectedCountry = CountryProvider.GetCountry(isocode);
if (await TryUpdateModelAsync<Country>(SelectedCountry, "SelectedCountry", c => c.Name, c => c.IsoCode, c => c.PrimaryLanguage))
{ ..... }
*/
return RedirectToPage("Data");
}
}
The page comes up just fine, everything is peachy, and I can edit the cities' name and population - no problem. When I click on "Update", the post method on the PageModel class is called - all seems just great. When I inspect the HttpContext.Form, I can see the values for the cities names and populations that I entered - so all appears to be fine.
BUT: after calling the TryUpdateModelAsync method, the citiesForCountry list is empty - no entries anymore, data entered manually is not applied :-(
Same happens when I'm using the SelectedCountry bind property - it's fine after being fetched from the provider, it has its list of cities (with the stored values), but after I call TryUpdateModelAsync, that list of cities is wiped out and the new values aren't stored anywhere....
I also tried to get the "view model" of type Country passed into my OnPostAsync method - like I used to be doing it with ASP.NET MVC back in the days:
public async Task<IActionResult> OnPostAsync(string isocode, Country edited)
I do get the basic information of the country - but again, the master/child Cities are not set, not populated with the values I've entered on the page.
So what am I missing here? I'm thinking there must be a detail I'm overlooking - but I can't seem to make sense of any of the articles, blog posts, tutorials etc. I've seen.... I seem to be doing exactly what they describe - alas, in my case, the data just doesn't quite make it into my view model (or rather: Razor PageModel) on post......