0
votes

I'm currently working on a form where you can create a new car which gets saved into a list of cars in my database. However, when you create a car, you can also select a brand from a drop down list. I've inserted the values of the options from a table/model which is called Brands. Right now, you can choose a brand, however, when I click sumbit everything other than the brand gets saved.

*I added the first row manually in mssql, that's why the first car has a brand assigned to it

Is it that I've written the wrong thing in the value attribute of the option tag or does the issue lie in something else?

Create.cshtml.cs


namespace CarRental.Pages.CarsList
{
    public class CreateModel : PageModel
    {

        private readonly ApplicationDbContext _db;
        public CreateModel(ApplicationDbContext db)
        {
            _db = db;
        }
        [BindProperty]
        public Cars Car { get; set; }


        public IList<Brands> Brands { get; set; }
        public void OnGet()
        {
            // going inside the DB, retrievieng all the brands and storing them in the IList
            Brands = _db.Brands.ToList();
        }

      

        public async Task<IActionResult> OnPost(Cars carObj)
        {
            if (ModelState.IsValid)
            {
                //add item in a que so that it can be pushed to the database
                _db.Cars.AddAsync(Car);
                //save changes to the database, aka push changes to the database
                await _db.SaveChangesAsync();

                //once the changes are pushed to the database
                return RedirectToPage("Index");
            } else
            {
                return Page();
            }
        }
    }
}

Create.cshtml

@page
@model CarRental.Pages.CarsList.CreateModel
@{
    ViewData["Title"] = "Create";
}

<h2 class="text-info">Create New Book</h2>
<br />

<div class="border container" style="padding:30px;">
    <form method="post">
        <div class="text-danger" asp-validation-summary="ModelOnly"></div>
        <div class="form-group row">
            <div class="col-3">
                <label asp-for="Car.LicensePlate"></label>
            </div>
            <div class="col-6">
                <input asp-for="Car.LicensePlate" class="form-control" />
            </div>

        </div>
        <div class="form-group row">
            <div class="col-3">
                <label asp-for="Car.Brand"></label>
            </div>
            <div class="col-6">
                <select asp-for="Car.Brand" class="form-control">
                  
                    @foreach (var item in Model.Brands)
                    {
                    <option value=">@Html.DisplayFor(m => item.Brand)">@Html.DisplayFor(m => item.Brand)</option>
                    }
                   
                </select>
            </div>

        </div>
        <div class="form-group row">
            <div class="col-3">
                <label asp-for="Car.Price"></label>
            </div>
            <div class="col-6">
                <input asp-for="Car.Price" class="form-control" />
            </div>

        </div>

        <div class="form-group row">
            <div class="col-3 offset-3">
                <input type="submit" value="Create" class="btn btn-primary form-control" />
            </div>
            <div class="col-3">
                <a asp-page="Index" class="btn btn-success form-control">Back to List</a>
            </div>
        </div>
    </form>
    @Html.ValidationSummary();
</div>

Brands.cs

namespace CarRental.Models
{
    public class Brands
    {
        [Key]
        public string Brand { get; set; }
    }
}

My Cars.cs model, incase that's of interest

namespace CarRental.Models
{
    public class Cars
    {
        [Key]
        public string LicensePlate { get; set; }
        public Brands Brand { get; set; }
        [Required]
        public float Price { get; set; }
        [Required]
        public bool StatusRented { get; set; } = true;
        
        public DateTime? StartDate { get; set; }

    }
}

Thank you in advance!

2
I think there's at least one spot here where you mean to have a single Brand, but are referring to a collection. Your Cars model has a Brands property and probably should be a single thing. Either that, or the extra S is just kinda confusing if it's singleNikki9696
I also wonder if this is a typo, in your post, you save Cars but the param is carObjNikki9696
It was originally a typo and then once I realised that I should've written it in singular, I didn't bother changing it and just stuck with it as I didn't think I'd show this to anyone. I'm sorry for the confusion, I'll definitely think about it next time!jrwebbie

2 Answers

1
votes

As far as I know, if we want to use asp.net core model binding to bind the complex types. You should make sure the Prefix = parameter name.

Model binding starts by looking through the sources for the key Instructor.ID. If that isn't found, it looks for ID without a prefix.

Like below this:

You have set asp-for="Car.LicensePlate", that means it will send the data like this:

enter image description here

Since your post method's parameter name is carObj, so the modelbinding couldn't find the right property name.

You should modify the parameter name to Car and then it will work well.

Besides, I suggest you should modify the <select asp-for="Car.Brand" class="form-control"> to <select asp-for="Car.Brand.Brand" class="form-control"> then asp.net core will bind the Brand in the car.

Also I found you set the <option value=">@Html.DisplayFor(m => item.Brand)"> , this also doesn't generate the right value. It will generate the value as >Microsoft.AspNetCore.Mvc.ViewFeatures.StringHtmlContent instead of the right item brand value. I suggest you could directly use @item.Brand and then it will work well.

Image:

enter image description here

More details, you could refer to below example:

<div class="border container" style="padding:30px;">
    <form method="post">
        <div class="text-danger" asp-validation-summary="ModelOnly"></div>
        <div class="form-group row">
            <div class="col-3">
                <label asp-for="Car.LicensePlate"></label>
            </div>
            <div class="col-6">
                <input asp-for="Car.LicensePlate" class="form-control" />
            </div>

        </div>
        <div class="form-group row">
            <div class="col-3">
                <label asp-for="Car.Brand"></label>
            </div>
            <div class="col-6">
                <select asp-for="Car.Brand.Brand" class="form-control">

                    @foreach (var item in Model.Brands)
                    {
                        <option value=">@Html.DisplayFor(m => item.Brand)">@Html.DisplayFor(m => item.Brand)</option>
                    }

                </select>
            </div>

        </div>
        <div class="form-group row">
            <div class="col-3">
                <label asp-for="Car.Price"></label>
            </div>
            <div class="col-6">
                <input asp-for="Car.Price" class="form-control" />
            </div>

        </div>

        <div class="form-group row">
            <div class="col-3 offset-3">
                <input type="submit" value="Create" class="btn btn-primary form-control" />
            </div>
            <div class="col-3">
                <a asp-page="Index" class="btn btn-success form-control">Back to List</a>
            </div>
        </div>
    </form>
    @Html.ValidationSummary();
</div> 

Code:

    [BindProperty]
    public Cars Car { get; set; }

    public IList<Brands> Brands { get; set; }


    public void OnGet()
    {
        Brands = new List<Brands> { new Brands { Brand="teta" }, new Brands { Brand="tetb" } };

    }

    public async Task<IActionResult> OnPost(Cars Car) {
        return Page();
    }

Result:

enter image description here

0
votes

Try to change

asp-for="Car.Brand" 

to

asp-for="Car.Brand.Brand"