Search code examples
c#asp.netroutesparameter-passingrazor-pages

How to Pass Value Back to Previous Razor Page?


I have an app that is structured as follows: Table 1 = Client Tables 2 = Panels

Each client can have multiple panels. When I submit my Create Client page, my app will navigate to and open the Create Panel page (passing the new Client.Id to the Create Panel page). When I submit the Create Panel page, it returns to the Edit Client page where you can view the panel inside the Edit Client page. From there, you can either Update the Edit Client page and return to the Client Index or just return to the Client Index if you didn't change the client portion of the Edit Client screen. This all works.

My issue is that on each Panel in the Edit Client screen, I have Edit and Delete Panel buttons. I use these to navigate to a specific panel for that specific client and make changes or delete the panel. The issue I have is that I am having trouble passing the ClientId back from the Edit Panel page to the Edit Client page. I get a NULL exception.

I know I am missing something, but when I attempt to add 'clientid' to the Edit Client OnGet, it never gets to that part of the code as it reads the .GetAttendees part, I think, and never reaches the 'clientid'. I have put breakpoints in and can see that the issue is the Client.Id itself not getting passed, just don't know the correct syntax for doing it.

Here are excerpts of my code:

Clients.Edit.cshtml

@page
@model SampleApp.Pages.Clients.EditModel

<form method="post">
    <input hidden asp-for="Client.Id" />
    <div class="border p-3 mt-4">
        <div class="row pb-2">
            <h2 class="text-primary pl-3">Edit Client</h2>
            <hr />
        </div>
        <div asp-validation-summary="All"></div>
        <h4>Demographics</h4>
        <br />
        <table class="table table-borderless" style="width:100%">
            <tr>
                <td style="width: 34%">
                    <div class="mb-3">
                        <label asp-for="Client.ClientFirstName"></label>
                        <input asp-for="Client.ClientFirstName" class="form-control" />
                        <span asp-validation-for="Client.ClientFirstName" class="text-danger"></span>
                    </div>
                </td>
                <td style="width: 34%">
                    <div class="mb-3">
                        <label asp-for="Client.ClientLastName"></label>
                        <input asp-for="Client.ClientLastName" class="form-control" />
                        <span asp-validation-for="Client.ClientLastName" class="text-danger"></span>
                    </div>
                </td>
            </tr>
        </table>
        <hr />
        <h4>Assigned Panels</h4>
        <table>
            <tr>
                <td>
                    <div class="w-75 btn-group" role="group">
                        <a asp-page="/Attendances/Create" asp-route-clientid="@Model.Client.Id" class="btn btn-primary mx-2" style="width:300px;">
                            Add Panel Attendance
                        </a>
                    </div>
                </td>
            </tr>
        </table>
        <br />
        <table class="table table-bordered table-striped width:100%">
            <thead>
                <tr>
                    <th>
                        Panel Id
                    </th>
                    <th>
                        Panel Assigned
                    </th>
                    <th>
                        Update Panel
                    </th>
                    <th>
                        Delete Panel
                    </th>
                </tr>
            </thead>
            <tbody>
                @for (var i = 0; i < Model.Client.GetAttendees.Count; i++)
                {
                    <tr>
                        <td style="width: 10%">
                            <div class="mb-3">
                                <input asp-for="Client.GetAttendees[i].ClientId" type="hidden" />
                                <input asp-for="Client.GetAttendees[i].Id" type="text" readonly class="form-control-plaintext" />
                            </div>
                        </td>
                        <td style="width: 30%">
                            <div class="mb-3">
                                <input asp-for="Client.GetAttendees[i].PanelAssigned" type="text" readonly class="form-control-plaintext" />
                            </div>
                        </td>
                        <td width="10%">
                            <div class="w-75 btn-group" role="group">
                                <a asp-page="/Attendances/Edit" class="btn btn-primary mx-2" asp-route-id="@Model.Client.GetAttendees[i].Id" asp-route-id="@Model.Client.GetAttendees[i].ClientId">
                                    <i class="bi-clipboard2-pulse"></i>
                                </a>
                            </div>
                        </td>
                        <td width="10%">
                            <div class="w-75 btn-group" role="group">
                                <a asp-page="/Attendances/Delete" class="btn btn-danger mx-2" asp-route-id="@Model.Client.GetAttendees[i].Id" asp-route-id="@Model.Client.GetAttendees[i].ClientId">
                                    <i class="bi bi-trash"></i>
                                </a>
                            </div>
                        </td>
                    </tr>
                }
        </table>
        <div>
            <button type="submit" class="btn btn-primary" style="width:300px;">Update -> Return to Client List</button>
            <a asp-page="Index" class="btn btn-secondary" style="width: 300px;">Return to Client List</a>
        </div>
    </div>
</form>

@section Scripts
{
    <partial name="_ValidationScriptsPartial"/>
}

Clients.Edit.cs

namespace SampleApp.Pages.Clients;

[BindProperties]

public class EditModel : PageModel
{
    private readonly ApplicationDbContext _db;

    public Client Client { get; set; }
    public Attendance Attendance { get; set; }

    public EditModel(ApplicationDbContext db)
    {
        _db = db;
    }

    public void OnGet(int id)
    {
        Client = _db.Client
                           .Include(client => client.GetAttendees)
                           .FirstOrDefault(client => client.Id == id);
    }

    public async Task<IActionResult> OnPost()
    {
        if (ModelState.IsValid)
        {
            _db.Update(Client);
            await _db.SaveChangesAsync();
            TempData["success"] = "Client updated successfully.";
            return RedirectToPage("/Clients/Index");
        }
        return Page();
    }
}

Attendances.Edit.cshtml

@page
@model SampleApp.Pages.Attendances.EditModel

<form method="post">
    <input hidden asp-for="Attendance.Id" />
    <div class="border p-3 mt-4">
        <div class="row pb-2">
            <h2 class="text-primary pl-3">Edit Client Attendance</h2>
            <hr />
        </div>
        <div asp-validation-summary="All"></div>
        <table class="table table-borderless" style="width:100%">
        <tr>
            <td style="width: 20%">
                <div class="mb-3">
                    <label asp-for="Attendance.ClientId"></label>
                    <input asp-for="Attendance.ClientId" name="clientid" class="form-control"/>
                    <span asp-validation-for="Attendance.ClientId" class="text-danger"></span>
                </div>
            </td>
            <td style="width: 80%">
                <div class="mb-3">
                    <label asp-for="Attendance.PanelAssigned"></label>
                    <select asp-for="Attendance.PanelAssigned" id="Select1" class="form-select">
                        <option value="">---Select Panel---</option>
                        @if (Model.DisplayPanelData != null)
                        {
                            @foreach (var item1 in Model.DisplayPanelData.OrderBy(x => x.PanelName))
                            {
                                <option value="@item1.PanelName" selected="@(item1.PanelName.ToString()==Model.Attendance.PanelAssigned?true:false)">@item1.PanelName</option>
                            }
                        }
                    </select>
                </div>
            </td>
        </tr>
        </table>
        <div>
            <button type="submit" class="btn btn-primary" style="width:300px;">Update -> Return to Client</button>
        </div>
    </div>
</form>

@section Scripts
{
      await Html.RenderPartialAsync("_ValidationScriptsPartial");
}

Attendances.Edit.cs

namespace SampleApp.Pages.Attendances;

[BindProperties]

public class EditModel : PageModel
{
    private readonly ApplicationDbContext _db;
    public Attendance Attendance { get; set; } = new Attendance();
    public Client Client { get; set; } = new Client();
    public EditModel(ApplicationDbContext db)
    {
        _db = db;
    }

    public IEnumerable<Panel> DisplayPanelData { get; set; }

    public void OnGet(int id)
    {
        Attendance = _db.Attendance.Find(id);

        DisplayPanelData = _db.Panel.ToList();
    }

    public async Task<IActionResult> OnPost()
    {
        if (ModelState.IsValid)
        {
            _db.Update(Attendance);
            await _db.SaveChangesAsync();
            TempData["success"] = "Client Attendance updated successfully.";
            ViewData["clientid3"] = Attendance.ClientId;
            return RedirectToPage("/Clients/Edit", new { id = ViewData["clientid3"] });
        }
        return Page();
    }
}

Client Model:

namespace SampleApp.Model
{
    public class Client
    {
        [Key]
        [Required]
        public int Id { get; set; }

        [ForeignKey("ClientId")]
        public List<Attendance>? GetAttendees { get; set; }

        [Display(Name = "Client First Name")]
        public string? ClientFirstName { get; set; }

        [Display(Name = "Client Middle Initial")]
        public string? ClientMI { get; set; }

        [Display(Name = "Client Last Name")]
        public string? ClientLastName { get; set; }
    }
}

Attendance Model:

namespace SampleApp.Model
{
    public class Attendance
    {
        [Key]
        [Required]
        public int Id { get; set; }

        [Display(Name ="Client Id")]
        public int? ClientId { get; set; }
        public Client? Client { get; set; }

        [Display(Name = "Panel Assigned")]
        public string? PanelAssigned { get; set; }
    }
}

Thanks for any and all assistance you can provide. My Delete Panel page seems to have the same issue. From what I think is wrong, I am simply not understanding how to write my OnGet for multiple instances of a value?


Solution

  • Figured it out. As so often I have found, it is the tiniest thing. Simply needed to remove name="clientid" from

    on the Attendances.Edit.cshtml page. I must have placed it there in one of my iterations of trying to figure things out and forgot it was there until I began combing row by row.