locked
Button directing to incorrect controller RRS feed

  • Question

  • User1571524970 posted

    Hi guys,

    In my Booking View I need the button to submit the users date into the Db then pass the user to the School/BookingForm controller/action but the button is passing the user back to the School/Booking controller/action for some reason and I get a server error:

    The model item passed into the dictionary is of type 'CampBookingSys.Models.School', but this dictionary requires a model item of type 'System.Collections.Generic.List`1[CampBookingSys.Models.Datepicker]'.

    Here's my view form:

    <form asp-controller="School" asp-action="Booking" method="post">
    
        <br />
        <div>
            <label for="RollNumber">School Roll Number:</label>
            <input asp-for="School.RollNumber" id="txtRoll" name="RollNumber" />
        </div>
        <br />
        <div>
            <label for="Date">Choose Date:</label>
            <input asp-for="School.Date" id="txtDate" name="Date" />
        </div>
        <br />
        <input type="submit" value="Submit" onclick="@("window.location.href='" + @Url.Action("BookingForm", "School") + "'");" /> **This is passing me to wrong controller?
    </form>

    Controllers:

    namespace CampBookingSys.Controllers
    {
        public class SchoolController : Controller
        {
            private CampBookingSysDb db = new CampBookingSysDb();
    
            // GET: School
            public ActionResult Index()
            {
                return View();
            }
    
            [HttpGet]
            public ActionResult Booking()
            {
                var model = db.Dates.ToList();
                return View(model);
            }
    
            [HttpPost]
            public ActionResult Booking(School model)
            {
                //insert Date into row in SchoolDb which matches RollNumber
                School school = db.Schools.First(m => m.RollNumber == model.RollNumber);
                school.Date = model.Date;
                db.SaveChanges();
    
                //make used date unavailable in datepicker
                Datepicker date = db.Dates.First(m => m.Date == model.Date);
                db.Dates.Remove(date);
                db.SaveChanges();
    
                return View(model);
            }
    
            [HttpGet]
            public ActionResult BookingForm(School model)
            {
                School school = db.Schools.First(m => m.RollNumber == model.RollNumber);
                return View(school);
            }
    
        }
    }

    Does anybody know why I am getting passed to the wrong controller after pressing the submit button?

    Cheers

    Saturday, August 17, 2019 8:59 PM

Answers

  • User753101303 posted

    See https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-2.2#the-form-action-tag-helper ie what if you try :

    <input type="submit" value="Submit" asp-action="BookingForm" />

    and make BookingForm a post action?  

    It seems you plan later to use a date picker (but it's not working for now ?). From a UI perspective updating the date seems a bit weird (or it is first null ?)

    As the role number is unique, I would expect rather the usual pattern ie showing a list of roll numbers with possibly a search UI and then click to show an edit view (his is to manage the actual inscription date to a school for students ???)

    Edit: in short from a technical point of view ASP.NET Core allows to control where the form and each submit button inside this form will post form data. Behind the scene it uses the "formaction" HTML5 attribute which allows to override the form level "action" attribute.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, August 18, 2019 2:31 PM

All replies

  • User753101303 posted

    Hi,

    You asked the browser to point to a new location but the default button behavior (ie submittting the form) still happens. A suggestion could be to append ";return false;" to your current handler so that the submit is cancelled. My personal preference is to just use type="button" when I don't want a submit button.

    That said it still won't work as your get request won't post form fields.

    Not 100% sure about your intent. It seems you'll perhaps have two forms one for a search and one for editing ? You could just change asp-action so that each form points to its own action. You can also use asp-action on a submit button to have multiple buttons in a single form, some of them posting to their own action.

    Sunday, August 18, 2019 9:51 AM
  • User1571524970 posted

    PatriceSc

    Hi,

    You asked the browser to point to a new location but the default button behavior (ie submittting the form) still happens. A suggestion could be to append ";return false;" to your current handler so that the submit is cancelled. My personal preference is to just use type="button" when I don't want a submit button.

    That said it still won't work as your get request won't post form fields.

    Not 100% sure about your intent. It seems you'll perhaps have two forms one for a search and one for editing ? You could just change asp-action so that each form points to its own action. You can also use asp-action on a submit button to have multiple buttons in a single form, some of them posting to their own action.

    Hi Patrice,

    Thanks a lot for your reply. The database includes 100s of records, each record is identified by its own unique RollNumber. My intention is to firstly take a RollNumber and Date from the user with the first form (Booking action) i.e. when the user submits the 2 form fields, RollNumber will be used to find the corresponding database row and enter/update the Date. After this happens I want the user to be redirected to the BookingForm action, which takes the same school object (matching the RollNumber) and uses this object to pre-populate all the BookingForm fields, using the data from the database i.e. RollNumber, Date, SchoolName, SchoolAddress etc. will all be filled out automatically for the user when they are redirected from Booking action the BookingForm action.

    Is this possible? If I haven't made my objectives clear enough please advise 

    Any help would be greatly appreciated! :)

    Cheers

    Sunday, August 18, 2019 1:14 PM
  • User753101303 posted

    See https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-2.2#the-form-action-tag-helper ie what if you try :

    <input type="submit" value="Submit" asp-action="BookingForm" />

    and make BookingForm a post action?  

    It seems you plan later to use a date picker (but it's not working for now ?). From a UI perspective updating the date seems a bit weird (or it is first null ?)

    As the role number is unique, I would expect rather the usual pattern ie showing a list of roll numbers with possibly a search UI and then click to show an edit view (his is to manage the actual inscription date to a school for students ???)

    Edit: in short from a technical point of view ASP.NET Core allows to control where the form and each submit button inside this form will post form data. Behind the scene it uses the "formaction" HTML5 attribute which allows to override the form level "action" attribute.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, August 18, 2019 2:31 PM
  • User1571524970 posted

    Thanks for the reply Patrice,

    The Datepicker is used to show a list of available dates to the user (a user is a specific school which is identified by their RollNumber). 1 available date can be selected by a user (a school) and once this date is selected it is removed from the Datepicker so other users (schools) can not choose the same date

    booking

    I have 2 Dbs; a School Db which holds 100s of records of schools with columns such as: RollNumber, SchoolName, SchoolAddress, TeacherName, BookingDate[which is initially Null], and a Booking Db (holds the same information, but each row represents 1 booking from a school). Once a user (a school) enters their RollNumber and Date I want to find the row in the Schools Db which matches the same RollNumber and then enter the Date. I then want to pass the user and the school object to the BookingForm action/view. The BookingForm view will have form fields corresponding to columns in the School Db (RollNumber, SchoolName, SchoolAddress etc.). I will use the school object which was passed into the HttpGet BookingForm action, to automatically populate these fields so that the user can review the information then use a HttpPost BookingForm action to submit the entry into the Booking Db.

    Hope this makes my intentions more clear :) is what I am trying to do even possible?

     thank you for your time

    Sunday, August 18, 2019 3:00 PM
  • User1571524970 posted

    OK so I have tried to use return RedirectToAction and passing the school object with it. Here are my controllers as it stands:

    namespace CampBookingSys.Controllers
    {
        public class SchoolController : Controller
        {
            private CampBookingSysDb db = new CampBookingSysDb();
    
            // GET: School
            public ActionResult Index()
            {
                return View();
            }
    
            [HttpGet]
            public ActionResult Booking()
            {
                var model = db.Dates.ToList();
                return View(model);
            }
    
            [HttpPost]
            public ActionResult Booking(School model)
            {
                //insert Date into row in SchoolDb which matches RollNumber
                School school = db.Schools.First(m => m.RollNumber == model.RollNumber);
                school.Date = model.Date;
                db.SaveChanges();
    
                //make used date unavailable in datepicker
                Datepicker date = db.Dates.First(m => m.Date == model.Date);
                db.Dates.Remove(date);
                db.SaveChanges();
    
                //return View(model);
                return RedirectToAction("BookingForm", "School", new RouteValueDictionary(school));
            }
    
            [HttpGet]
            public ActionResult BookingForm(School model)
            {
                School school = db.Schools.First(m => m.RollNumber == model.RollNumber);
                return View(school);
            }
    
            [HttpPost]
            [ActionName("BookingForm")]
            public ActionResult BookingFormPost(School model)
            {
                //This action will enter Booking into Booking Db
                return View();
            }
    
        }
    }

    and it worked :)

    thanks again for your time Patrice

    Sunday, August 18, 2019 6:04 PM