Search code examples
c#asp.net-corerazorrazor-pages

If a second form is submitted on my razor page, will this automatically clear all the bindingprops in the pagemodel populated by the first form?


I am writing a simple ASP.NET Core web app using Razor pages, and I am quite new to it. I was debugging because I saw some unexpected behavior using multiple forms on the page. One form for displaying available rooms depending on room type and startdate/endate, and many others for the user to be able to click "Book room" on each room card (all use the same action handler to simply book the corresponding room). The list of available rooms (with the "Book now"-forms show after submitting the first one.

I noticed that after pressing "Book room" the page started to act weird, now after submitting the first form again the action handler of the second form was called, not the OnPost standard method that was called the first time. I also noticed that the bind properties in the page model was now set to null or 0001-01-01 for the dates.

  1. Do I need to specify an action handler for all forms if I have many of them (I thought you did not have to do so for the first one and that it could only have the method="post" for it to understand, while the others need action handler for it to distinguish between them).
  2. Is it the case that when submitting a second form, the bind properties are set to null or standard vals? Meaning that the old props submitted in the first form will not persist?

I think that it would be better for me to have separated these things into different pages instead somehow, but I am still interested in knowing how to work this out, thanks for any help!


Solution

  • If a second form is submitted on my razor page, will this automatically clear all the bindingprops in the pagemodel populated by the first form?

    Yes. In Razor page, when submit the form, we can get the form value from the form fields, in your scenario, if these form fields only in the first form, not the second form. Then when submit the second form to different handler method, the bind properties in the page model might be null or default value.

    To persist the value in the first form, you can use TempData or Session to store the first form field value, and then in the second form submitted handler method, reset the related page model properties.

    Do I need to specify an action handler for all forms if I have many of them (I thought you did not have to do so for the first one and that it could only have the method="post" for it to understand, while the others need action handler for it to distinguish between them).

    Yes, you can do that, then your code will be clearer. Just pat attention to the asp-page attribute, asp-page-handler attribute, asp-route-xxx attribute and the method attribute.

    Is it the case that when submitting a second form, the bind properties are set to null or standard vals? Meaning that the old props submitted in the first form will not persist?

    To persist the first form data, you can use TempData or Session to store the first forum fields.

    Here is a simple sample you can check it:

    Index.cshtml: in this page, there have two forms, the first form is used to filter data, and the second form is used to change the Room booking status.

    @page "/roomindex"
    @model RazorPageSample.Pages.RoomBooking.IndexModel
    
    @{
        ViewData["Title"] = "Index";
    }
    
    <h1>Index</h1>
    
    <p>
        <a asp-page="Create">Create New</a>
    </p>
    
    <form asp-page="./roomindex" method="get">
        <div class="form-actions no-color">
            <p>
                IsBooked:
                <select asp-for="IsBooked" asp-items="@((List<SelectListItem>)ViewData["BookStatus"])">
                    <option value="All">Pick one</option>
                </select>
                <input type="submit" value="Search" class="btn btn-primary" /> |
                <a asp-page="./roomindex">Back to full List</a>
            </p>
        </div>
    </form>
    <table class="table">
        <thead>
            <tr>
                <th>
                    @Html.DisplayNameFor(model => model.Room[0].Name)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Room[0].Description)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Room[0].IsBooked)
                </th>
                <th>Navigate</th>
                <th>Handler</th>
            </tr>
        </thead>
        <tbody>
    @foreach (var item in Model.Room) {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.Name)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Description)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.IsBooked)
                </td>
                <td>
                    <a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
                    <a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
                    <a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
                </td>
                <td>
                    <div class="row">
                        <div class="col-lg-1">
                            <form asp-page-handler="edit" asp-route-id="@item.Id" method="post">
                                    <button class="btn btn-primary"> @(item.IsBooked ? "UnBooking" : "Booking")</button>
                                </form>
                        </div>
                    </div>
                </td>
            </tr>
    }
        </tbody>
    </table>
    

    Index.cshtml.cs file: Here we use the TempData attribute on the IsBooked property, when submit the first form, we can get the form data from the OnGet method's parameter, after submitting the second form, we can see the IsBooked is not null.

    public class IndexModel : PageModel
    {
        private readonly ApplicationDbContext _context;
    
        public IndexModel(ApplicationDbContext context)
        {
            _context = context;
        }
    
        public IList<Room> Room { get;set; } = default!;
    
        [BindProperty(SupportsGet = true), TempData]
        public string IsBooked { get; set; }
    
        public void OnGet(string isBooked)
        {
            IsBooked = isBooked; //set the first form fields
            SetInitialData();
        } 
    
        public void SetInitialData()
        {
            //set the book status.
            ViewData["BookStatus"] = new List<SelectListItem>()
            {
                new SelectListItem(){ Value="True", Text="True"},
                new SelectListItem(){Value="False", Text="False"},
            };
    
            //Display data based on booking information
            switch (IsBooked)
            {
                case "True":
                    Room =  _context.Room.Where(c => c.IsBooked == true).ToList();
                    break;
                case "False":
                    Room =  _context.Room.Where(c => c.IsBooked == false).ToList();
                    break;
                default:
                    Room =  _context.Room.ToList();
                    break;
            };
    
        }
        //page handler to modify the booking status
        public  void OnPostEdit(int id)
        {
             var item = _context.Room.Where(c=>c.Id == id).FirstOrDefault();
            item.IsBooked =  item.IsBooked ? false : true;
            _context.SaveChanges();
            TempData.Keep();
           SetInitialData();
        } 
    }
    

    Note: In the OnPostEdit method, we use the TempData.Keep() method to keep the tempdata value.

    The test screenshot as below:

    when page load, we can filter data based on the DropDownList:

    enter image description here

    After select the Booking status, and click the Search button, the first form submitted and the result like this:

    enter image description here

    Then, we can click the Booking/UnBooking button to change the room status, the second form submit, after unbooking the 1002 room, the result as below:

    enter image description here

    As we can see, the first form data persist.

    If you want to use session to store the first form field value, you can refer to Session State in Razor Pages and Session and state management in ASP.NET Core

    Other Resource:

    Model Binding In Razor Page.

    TempData In Razor Pages