简体   繁体   中英

Asp .Net Core 3.1 Razor Page: Complex model binding

I am struggeling with data binding and Razor pages

I was not able to find a solution. Propably I am asking not the right questions. So I hope you can help me out to point me to the right direction.

I want a page to create bookings to collect all necessary data to post it to a web api when everything is done.

On that page I want to collect necessary data for the wooking and want to add x Booking Details to the Booking.

Datamodel

public class Booking
{
   [Key]
   public int Id { get; set; }

   public string Reference { get; set; }

   public List<BookingDetail> BookingDetails { get; set; }
}
public class BookingDetail
{
   [Key]
   public int Id { get; set; }

   public int Pieces { get; set; }

   public string Marks { get; set; }
}

What I would like to to is to create a create page for a booking. So far I followed this instructions, which is working Link

This missing part is that I would like to add new Booking Details as well on the same Razor page.

So I want to see a list of all added booking Details and I want to have textboxes to add new booking Details.

My idea was to do the following, but I am receiving a System.NullReferenceException as Booking is null:

@page
@model Onlinebooking.Web.Pages.BookingModel
@{
    ViewData["Title"] = "Booking";
}

<h1>Booking4</h1>
<form method="post">
    Reference: <Input asp-for="Booking.Reference" /><br />
    Pieces: <input asp-for="Booking.BookingDetails[0].Pieces" /><br />
    Marks: <input asp-for="Booking.BookingDetails[0].Marks" /><br />
    <br />
    <input type="submit" value="submit" />
</form>

<form method="post" asp-page-handler="DeleteBookingDetails">
    @for (var i = 0; i < @Model.Booking.BookingDetails.Count(); i++)
    {
        @Html.LabelFor(x => x.Booking.BookingDetails[i].Pieces)
        @Html.LabelFor(x => x.Booking.BookingDetails[i].Marks)
    }
</form>

Is it even possible to do all that on one page or should I go in a different direction?

Thanks for your help!

There are a couple concepts I have had much difficulty with also in your question.

The first issue you are coming across is in the CSHTML.CS file. Initializing your variables will solve that problem.

public class BookingModel : PageModel
{
    private readonly DataDbContext _context;

    public BookingModel(DataDbContext context)
    {
        _context = context;
    }

    public List<Booking> Bookings { get; set; } = new List<Booking>();
    public Booking Booking { get; set; } = new Booking();
    public BookingDetail BookingDetail { get; set; } = new BookingDetail();

    public void OnGet()
    {
        Bookings = _context.Bookings.Include(x => x.BookingDetails).ToList();
    }
}

And on the CSHTML side I would slightly modify how you are referencing the labels and printing your FOR loops.

<form method="post" asp-page-handler="DeleteBookingDetails">
<table>
    <thead>
        <tr>
            <th><label asp-for="BookingDetail.Pieces" class="control-label"></label></th>
            <th><label asp-for="BookingDetail.Marks" class="control-label"></label></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var booking in Model.Bookings)
        {
            foreach (var bookingDetail in booking.BookingDetails)
            {
                <tr>
                    <td>@bookingDetail.Pieces</td>
                    <td>@bookingDetail.Marks</td>
                </tr>
            }
        }
    </tbody>
</table>

I have not modified Booking or BookingDetail.

I believe you will be able to figure out the rest of your functionality from here.

Here is a demo to add and delete BookingDetai:

cshtml:

<form method="post">
    <Input asp-for="Booking.Id" hidden />
    Reference: <Input asp-for="Booking.Reference" /><br />
    Pieces: <input name="Booking.BookingDetails[@Model.Booking.BookingDetails.Count()].Pieces" /><br />
    Marks: <input name="Booking.BookingDetails[@Model.Booking.BookingDetails.Count()].Marks" /><br />
    <br />
    <input type="submit" value="submit" asp-page-handler="AddBookingDetails"/>
    <div hidden>
        @for (var i = 0; i < @Model.Booking.BookingDetails.Count(); i++)
        {
            <input asp-for="@Model.Booking.BookingDetails[i].Id" hidden />

            <input asp-for="@Model.Booking.BookingDetails[i].Pieces" hidden />

            <input asp-for="@Model.Booking.BookingDetails[i].Marks" hidden />


        }
    </div>
   
</form>

    <table>
        <thead>
            <tr>
                <th><label class="control-label">Pieces</label></th>
                <th><label class="control-label">Marks</label></th>
                <th><label class="control-label">Action</label></th>
            </tr>
        </thead>
        <tbody>
            @for (var i = 0; i < @Model.Booking.BookingDetails.Count(); i++)
            {
            <tr>
                <form method="post" >
                    <div hidden>
                        @for (var j = 0; j < @Model.Booking.BookingDetails.Count(); j++)
                        {
                            <input asp-for="@Model.Booking.BookingDetails[j].Id" hidden />

                            <input asp-for="@Model.Booking.BookingDetails[j].Pieces" hidden />

                            <input asp-for="@Model.Booking.BookingDetails[j].Marks" hidden />


                        }
                    </div>
                    <td>@Model.Booking.BookingDetails[i].Pieces</td>
                    <input name="Booking.Id" hidden value="@Model.Booking.Id" />
                    <input name="Booking.Reference" hidden value="@Model.Booking.Reference" />
                    <input name="BookingDetail.Id" hidden value="@Model.Booking.BookingDetails[i].Id" />
                    <td>@Model.Booking.BookingDetails[i].Marks</td>
                    <td><button asp-page-handler="DeleteBookingDetails">delete</button></td>
                </form>
            </tr>
            }
        </tbody>
    </table>

cshtml.cs(I use simple data to test it):

   public class CreateBookingModel : PageModel
    {
        [BindProperty]
        public Booking Booking { get; set; }
        [BindProperty]
        //BookingDetail is used to delete BookingDetail 
        public BookingDetail BookingDetail { get; set; }
        public static int count;
        public ActionResult OnGet()
        {
            List<BookingDetail> list = new List<BookingDetail> { new BookingDetail { Id = 1, Pieces = 2, Marks = "m1" }, new BookingDetail { Id = 2, Pieces = 1, Marks = "m2" } };
            Booking = new Booking { Id = 1, Reference = "r", BookingDetails = list };
            count = 2;
            return Page();
        }
        public ActionResult OnPostAddBookingDetails() {

            Booking.BookingDetails[Booking.BookingDetails.Count()-1].Id = ++count;

            return Page();
        }
        public ActionResult OnPostDeleteBookingDetails() {
            Booking.BookingDetails.RemoveAll(b => b.Id == BookingDetail.Id);
            return Page();
        }
    }

result: 在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM