Search code examples
asp.netroutesparameterssyntaxrazor-pages

Passing Value from Delete Razor Page


I have an app that is structured as follows: Table 1 = Client and Table 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. I then want the app to return to the Edit Client page. The issue I have is that I am having trouble passing the ClientId back from the Delete Panel page to the Edit Client page. I get a NULL exception.

I think my initial issue is that I was deleting the Panel Record BEFORE grabbing the ClientId from the record. I've only done a basic delete page before, so am not that familiar with how I could best approach this. I tried an approach similar to my Edit Panel, but that is where I was effectively grabbing the ClientId after it was gone.

Here is what I currently have for my Delete.Cshtml (additional fields deleted for brevity)

@page
@model SampleApp.Pages.Attendances.DeleteModel

<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">Delete Client From Panel</h2>
            <hr />
        </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" disabled class="form-control"/>
                </div>
            </td>
            <td style="width: 80%">
                <div class="mb-3">
                    <label asp-for="Attendance.PanelAssigned"></label>
                    <select asp-for="Attendance.PanelAssigned" id="Select1" disabled 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-danger" style="width:300px;">Delete -> Return to Client</button>
            <a asp-page="Index" class="btn btn-secondary" style="width: 300px;">Back to Client List</a>
        </div>
    </div>
</form>

And here is my Delete.cshtml.cs:

namespace SampleApp.Pages.Attendances;

[BindProperties]

public class DeleteModel : PageModel
{
    private readonly ApplicationDbContext _db;
    public Attendance Attendance { get; set; } = new Attendance();
    public Client Client { get; set; } = new Client();
    public DeleteModel(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()
    {
        ViewData["clientid4"] = Attendance.ClientId; //This didn't work either. Still showed null.
        {
            var AttendanceFromDb = _db.Attendance.Find(Attendance.Id);
            if (AttendanceFromDb != null)
            {
                _db.Attendance.Remove(AttendanceFromDb);
                await _db.SaveChangesAsync();
                TempData["success"] = "Client Attendance deleted successfully.";
                ViewData["clientid4"] = Attendance.ClientId; //Here seems to be too late.
                return RedirectToPage("/Clients/Edit", new { id = ViewData["clientid4"] });
            }
        }
        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 re: proper syntax and proper placement. Layman's terms please. I want to understand. :)


Solution

  • Does this work for you? I should think the id parameter already comes with the request and you just haven’t been using it.

    public void OnGet(int id)
    {
        //here you load the Attendance property using the requested ID:
        Attendance = _db.Attendance.Find(id);
    
        DisplayPanelData = _db.Panel.ToList();
    }
    
    public async Task<IActionResult> OnPost(int id)
    {
        //here you need to load it again, because the one you
        //loaded before was only valid for the GET request:
        var AttendanceFromDb = _db.Attendance.Find(id);
    
        //before you had this line, which doesn’t work because
        //Attendance is not loaded:
        //var AttendanceFromDb = _db.Attendance.Find(Attendance.Id);
    
        if (AttendanceFromDb != null)
        {
            _db.Attendance.Remove(AttendanceFromDb);
            await _db.SaveChangesAsync();
            TempData["success"] = "Client Attendance deleted successfully.";
    
            //here again, “Attendance” is not loaded so you can’t use it.
            //also you don’t need to manipuplate any ViewData because
            //you’re redirecting to a whole other page anyway.
            //ViewData["clientid4"] = Attendance.ClientId;
    
            //here I put the ClientId from the loaded AttendanceFromDB
            //object instead. I think that’s probably what you want?
            return RedirectToPage("/Clients/Edit", new { id = AttendanceFromDb.ClientId });
        }
        
        //you should probably still redirect to avoid duplicate submissions
        //see https://en.wikipedia.org/wiki/Post/Redirect/Get
        return Page();
    }