CyberAnt
CyberAnt

Reputation: 13

Pass ID between 2 controllers ASP.NET Core 3.1 MVC

I'm new to programming and I need your help. I'm trying to create a simple testing application (ASP.NET Core 3.1 MVC + EF). I've created 2 models (Event, Enrollment). The goal is to open the enrollment create form page with the selected EventId by clicking on the "Enroll" button in the Events/Index page. How should I pass the EventId to the EnrollmentsController? I tried to pass EventId in the Events/Index page using a form with hidden input, but I still don't know how to handle EventId correctly in EnrollmentsController.

Note: I don't wanna use SelectList in Enrollment's Create method and view.

I will be grateful for any help. Thank you!

UPDATE: Thanks to @PanagiotisKanavos I finally get the EventId in the URL, but it still doesn't feed into the form input. There is "0". What could be wrong?

Models
public class Event
  {
    public int EventId { get; set; }

    public string Name { get; set; }

    [DataType(DataType.Date)]
    public DateTime Date { get; set; }
  }

public class Enrollment
  {
    public int EnrollmentId { get; set; }

    public int EventId { get; set; }
    public Event Event { get; set; }

    [Display(Name ="First name")]
    public string FirstName { get; set; }

    [Display(Name = "Last name")]
    public string LastName { get; set; }

    [Display(Name ="Enrollment date")]
    [DataType(DataType.DateTime)]
    public DateTime EnrollmentDate { get; set; }
  }
Events/Index view
    @model IEnumerable<FormTest.Models.Event>

@{
  ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
  <a asp-action="Create">Create New</a>
</p>
<table class="table">
  <thead>
    <tr>
      <th>
        @Html.DisplayNameFor(model => model.Name)
      </th>
      <th>
        @Html.DisplayNameFor(model => model.Date)
      </th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    @foreach (var item in Model)
    {
      <tr>
        <td>
          @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
          @Html.DisplayFor(modelItem => item.Date)
        </td>
        <td>
          <a asp-action="Create" asp-controller="Enrollments" asp-route-id="@item.EventId" class="btn btn-primary">Enroll</a>
        </td>
      </tr>
    }
  </tbody>
</table>
Enrollments/Create view
@model FormTest.Models.Enrollment

@{
  ViewData["Title"] = "Create";
}

<h1>Create</h1>

<h4>Enrollment</h4>
<hr />
<div class="row">
  <div class="col-md-4">
    <form asp-action="Create">
      <div asp-validation-summary="ModelOnly" class="text-danger"></div>
      <div class="form-group">
        <label asp-for="EventId" class="control-label"></label>
        <input class="form-control" asp-for="EventId" name="EventId" />
      </div>
      <div class="form-group">
        <label asp-for="FirstName" class="control-label"></label>
        <input asp-for="FirstName" class="form-control" />
        <span asp-validation-for="FirstName" class="text-danger"></span>
      </div>
      <div class="form-group">
        <label asp-for="LastName" class="control-label"></label>
        <input asp-for="LastName" class="form-control" />
        <span asp-validation-for="LastName" class="text-danger"></span>
      </div>
      <div class="form-group">
        <label asp-for="EnrollmentDate" class="control-label"></label>
        <input asp-for="EnrollmentDate" class="form-control" />
        <span asp-validation-for="EnrollmentDate" class="text-danger"></span>
      </div>
      <div class="form-group">
        <input type="submit" value="Create" class="btn btn-primary" />
      </div>
    </form>
  </div>
</div>
EnrollmentsController Create method
// GET: Enrollments/Create
    public IActionResult Create(int eventId)
    {
      var newEnrollment = new Enrollment
      {
        EventId = eventId,
        FirstName = "John",
        LastName = "Doe",
        EnrollmentDate = DateTime.UtcNow
      };

      return View(newEnrollment);
    }

Here is the screen: enrollment/create

Upvotes: 1

Views: 2106

Answers (2)

Yiyi You
Yiyi You

Reputation: 18179

If you want to use asp-route-{value},you need to make sure the value name is consistent to the parameter name in action.Fo example,you use

public IActionResult Create(int eventId)

So that you need to use

 asp-route-eventId="@item.EventId"

Upvotes: 0

Panagiotis Kanavos
Panagiotis Kanavos

Reputation: 131492

The easiest option would be to not use a form but a link to the Enrollments controller. After all, the goal is to open the Enrollments page, not submit the enrollment :

<td>
 <a asp-controller="Enrollments" 
    asp-action="Create"
    asp-route-id="@item.EventID">Enroll</a>
</td>

The link can be made to look like a button with the proper Bootstrap styles :

<a asp-controller="Enrollments" 
   asp-action="Create"
   asp-route-id="@item.EventID"
   class="btn btn-primary" role="button" >
Enroll
</a>

The Controller action needs to accept the id as a parameter:

public IActionResult Create(int eventId)
{
    var newEnrollment=new Enrollment{ 
        EventId=eventId,
        ...
    };
    return View(newEnrollment);
}

The same routing tag helpers can be used in a form :

<td>
    <form asp-controller="Enrollments" 
          asp-action="Create"
          asp-route-id="@item.EventID" method="post">
        <button type="submit" value="Enroll"></button>
    </form>
</td>

Using a form like this is a bit weird though. This would require adding an Index(id) action that responds to POST along with the Index(id) that responds to GET.

The ASP.NET Core MVC Tutorial shows how to create an application that lists Todo items, allows editing, deleting and redirecting from the list to the edit pages.

The Tag Helpers in Forms page explains how tag helpers like asp-controller, asp-action and asp-route-* can be used to specify controllers, actions and parameters in a form.

Upvotes: 1

Related Questions