#
Click to Edit
#
Implementing Click-to-Edit with htmx and ASP.NET Core
The Click-to-Edit pattern is a sleek way to provide inline editing capabilities. Instead of redirecting to a separate edit page, htmx allows you to swap the display view with an edit form in-place, and then swap back once the update is complete.
#
1. The Display State
Initially, we show the contact information. The container is configured to handle the swap when an inner element triggers an htmx request.
_DisplayContactForm.cshtml
@model Contact
<div hx-target="this" hx-swap="outerHTML">
<div><label asp-for="@Model.FirstName"></label>: @Model.FirstName</div>
<div><label asp-for="@Model.LastName"></label>: @Model.LastName</div>
<div><label asp-for="@Model.Email"></label>: @Model.Email</div>
<button hx-get="@Url.Page("Index", "EditContact")" class="btn btn-primary">
Click To Edit
</button>
</div>
hx-target="this": Tells htmx to replace the currentdivwith the response.hx-swap="outerHTML": Ensures the entiredivis replaced, not just its content.hx-get: Requests the edit form from theEditContacthandler.
#
2. The Edit State
When the "Click To Edit" button is pressed, the server returns a partial view containing the form.
_EditContactForm.cshtml
@model Contact
<form hx-put="@Url.Page("Index", "ReplaceContact")" hx-target="this" hx-swap="outerHTML">
@Html.AntiForgeryToken()
<div>
<label asp-for="@Model.FirstName">First Name</label>
<input asp-for="@Model.FirstName">
</div>
<div>
<label asp-for="@Model.LastName">Last Name</label>
<input asp-for="@Model.LastName">
</div>
<div>
<label asp-for="@Model.Email">Email Address</label>
<input asp-for="@Model.Email">
</div>
<button class="btn btn-primary">Submit</button>
<button class="btn btn-secondary" hx-get="@Url.Page("Index", "DisplayContact")">Cancel</button>
</form>
hx-put: Submits the form data to theReplaceContacthandler.- The "Cancel" button uses
hx-getto fetch the display version again, discarding changes.
#
3. The Backend: C# PageModel
The Index.cshtml.cs file manages the transitions between these states by returning the appropriate partial views.
Index.cshtml.cs
public class Index : PageModel
{
private IContactService contactService;
// ... constructor ...
// Fetches the edit form
public PartialViewResult OnGetEditContact()
{
var contact = contactService.Get(1);
return Partial("_EditContactForm", contact);
}
// Handles the update and returns the display view
public IActionResult OnPutReplaceContact(Contact model)
{
contactService.Update(1, model);
return Partial("_DisplayContactForm", model);
}
// Handles cancellation
public PartialViewResult OnGetDisplayContact()
{
var contact = contactService.Get(1);
return Partial("_DisplayContactForm", contact);
}
}
#
Summary
This pattern provides a very "app-like" feel. By swapping small fragments of HTML, you avoid full page reloads and maintain the user's scroll position and context, all while keeping your logic cleanly separated in Razor Pages and C#.