Skip to content

Commit

Permalink
Add sample for htmx:afterOnLoad
Browse files Browse the repository at this point in the history
  • Loading branch information
dodyg committed Aug 12, 2024
1 parent 7e229b5 commit 67a8493
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 10 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ You can find samples on new features availabel in ASP.NET Core 9(3) [here](/proj
| [Generic Hosting](/projects/generic-host) | 9 | |
| [gRPC](/projects/grpc) (including grpc-Web) | 12 | |
| [Health Check](/projects/health-check) | 6 | |
| [HTMX](/projects/htmx) | 39 | |
| [HTMX](/projects/htmx) | 40 | |
| [IHttpClientFactory](/projects/httpclientfactory) | 4 | |
| [IHostedService](/projects/ihosted-service) | 2 | |
| [Logging](/projects/logging) | 5 | |
Expand Down
23 changes: 14 additions & 9 deletions projects/htmx/Readme.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# HTMX (39)
# HTMX (40)

This example shows various examples on how to integrate [HTMX](https://htmx.org/) with ASP.NET Core Minimal API. We will be using [HTMX Nuget Package](https://www.nuget.org/packages/Htmx). We are using [HTMX 2](https://htmx.org/) in all samples.

Expand All @@ -24,14 +24,6 @@ This example shows various examples on how to integrate [HTMX](https://htmx.org/

This example shows how to pass values via HTTP headers using `hx-headers`.

* [htmx-config-request](htmx-config-request)

This examples shows how to listen to `htmx:configRequest` event to modify parameters to be sent to the server.

* [htmx-response-error](htmx-response-error)

This examples shows how to listen to `htmx:responseError` event to obtain AJAX response error information.

* [hx-confirm](hx-confirm)

This example shows how to use `hx-confirm` to ask for user confirmation before making a request
Expand Down Expand Up @@ -134,6 +126,19 @@ This example shows various examples on how to integrate [HTMX](https://htmx.org/

This example shows how to show a modal dialog using HTMX and Bootstrap 5.

## Events

* [htmx-config-request](htmx-config-request)

This examples shows how to listen to `htmx:configRequest` event to modify parameters to be sent to the server.

* [htmx-response-error](htmx-response-error)

This examples shows how to listen to `htmx:responseError` event to obtain AJAX response error information.

* [htmx-after-on-load](htmx-after-on-load)

This example shows how to listen to `htmx:afterOnLoad` event, which is trigerred after the AJAX response has finished.

## Response Headers

Expand Down
24 changes: 24 additions & 0 deletions projects/htmx/htmx-after-on-load/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"workbench.colorCustomizations": {
"activityBar.activeBackground": "#0c5dc8",
"activityBar.background": "#0c5dc8",
"activityBar.foreground": "#e7e7e7",
"activityBar.inactiveForeground": "#e7e7e799",
"activityBarBadge.background": "#f669a6",
"activityBarBadge.foreground": "#15202b",
"commandCenter.border": "#e7e7e799",
"sash.hoverBorder": "#0c5dc8",
"statusBar.background": "#094798",
"statusBar.debuggingBackground": "#985a09",
"statusBar.debuggingForeground": "#e7e7e7",
"statusBar.foreground": "#e7e7e7",
"statusBarItem.hoverBackground": "#0c5dc8",
"statusBarItem.remoteBackground": "#094798",
"statusBarItem.remoteForeground": "#e7e7e7",
"titleBar.activeBackground": "#094798",
"titleBar.activeForeground": "#e7e7e7",
"titleBar.inactiveBackground": "#09479899",
"titleBar.inactiveForeground": "#e7e7e799"
},
"peacock.color": "#094798"
}
120 changes: 120 additions & 0 deletions projects/htmx/htmx-after-on-load/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using Htmx;
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder();
builder.Services.AddAntiforgery();
var app = builder.Build();

app.UseAntiforgery();

app.MapGet("/", (HttpContext context, [FromServices] IAntiforgery anti) =>
{
var token = anti.GetAndStoreTokens(context);
var html = $$"""
<!DOCTYPE html>
<html>
<head>
<style>
li{
cursor:pointer;
}
</style>
<meta name="htmx-config" content='{ "antiForgery": {"headerName" : "{{ token.HeaderName}}", "requestToken" : "{{token.RequestToken }}" } }'>
</head>
<body>
<h1>htmx:afterOnLoad</h1>
<p>Click on the below links to see the response</p>
<ul>
<li id="get-trigger" hx-get="/htmx">GET</li>
<li id="post-trigger" hx-post="/htmx">POST</li>
<li id="put-trigger" hx-put="/htmx">PUT</li>
<li id="patch-trigger" hx-patch="/htmx">PATCH</li>
<li id="delete-trigger" hx-delete="/htmx"'>DELETE</li>
</ul>
<script src="https://unpkg.com/[email protected]" integrity="sha384-wS5l5IKJBvK6sPTKa2WZ1js3d947pvWXbPJ1OmWfEuxLgeHcEbjUUA5i9V5ZkpCw" crossorigin="anonymous"></script>
<script>
document.addEventListener("htmx:afterOnLoad", (evt) => {
let li = evt.detail.elt;
alert(li.id);
});

document.addEventListener("htmx:configRequest", (evt) => {
// This is for the anti-forgery token
let httpVerb = evt.detail.verb.toUpperCase();
if (httpVerb === 'GET') return;
let antiForgery = htmx.config.antiForgery;
if (antiForgery) {
// already specified on form, short circuit
if (evt.detail.parameters[antiForgery.formFieldName])
return;
if (antiForgery.headerName) {
evt.detail.headers[antiForgery.headerName]
= antiForgery.requestToken;
} else {
evt.detail.parameters[antiForgery.formFieldName]
= antiForgery.requestToken;
}
}
});
</script>
</body>
</html>
""";
return Results.Content(html, "text/html");
});

var htmx = app.MapGroup("/htmx").AddEndpointFilter(async (context, next) =>
{
if (context.HttpContext.Request.Method == "GET")
return await next(context);

await context.HttpContext.RequestServices.GetRequiredService<IAntiforgery>()!.ValidateRequestAsync(context.HttpContext);
return await next(context);
});

htmx.MapGet("/", (HttpRequest request) =>
{
if (request.IsHtmx() is false)
return Results.Content("");

return Results.Content($"GET => {DateTime.UtcNow}");
});

htmx.MapPost("/", (HttpRequest request) =>
{
if (request.IsHtmx() is false)
return Results.Content("");

return Results.Content($"POST => {DateTime.UtcNow}");
});

htmx.MapDelete("/", (HttpRequest request) =>
{
if (request.IsHtmx() is false)
return Results.Content("");

return Results.Content($"DELETE => {DateTime.UtcNow}");
});

htmx.MapPut("/", (HttpRequest request) =>
{
if (request.IsHtmx() is false)
return Results.Content("");

return Results.Content($"PUT => {DateTime.UtcNow}");
});

htmx.MapPatch("/", (HttpRequest request) =>
{
if (request.IsHtmx() is false)
return Results.Content("");

return Results.Content($"PATCH => {DateTime.UtcNow}");
});

app.Run();


12 changes: 12 additions & 0 deletions projects/htmx/htmx-after-on-load/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Listen to htmx:afterOnLoad event

This example shows how to listen to `htmx:afterOnLoad` ([doc](https://htmx.org/events/#htmx:afterOnLoad)).

> This event is triggered after an AJAX onload has finished. Note that this does not mean that the content has been swapped or settled yet, only that the request has finished.
```js
document.addEventListener("htmx:afterOnLoad", (evt) => {
let li = evt.detail.elt;
alert(li.id);
});
```
9 changes: 9 additions & 0 deletions projects/htmx/htmx-after-on-load/htmx-after-on-load.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>true</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Htmx" Version="1.8.0" />
</ItemGroup>
</Project>

0 comments on commit 67a8493

Please sign in to comment.