Skip to content

Commit

Permalink
Add more header hx-trigger example
Browse files Browse the repository at this point in the history
  • Loading branch information
dodyg committed Aug 2, 2024
1 parent 0cad42c commit c4ce345
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 3 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) | 33 | |
| [HTMX](/projects/htmx) | 34 | |
| [IHttpClientFactory](/projects/httpclientfactory) | 4 | |
| [IHostedService](/projects/ihosted-service) | 2 | |
| [Logging](/projects/logging) | 5 | |
Expand Down
8 changes: 6 additions & 2 deletions projects/htmx/Readme.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# HTMX (33)
# HTMX (34)

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 Down Expand Up @@ -143,4 +143,8 @@ This example shows various examples on how to integrate [HTMX](https://htmx.org/

* [HX-Trigger]

This example demonstrates how to use `HX-Trigger` response header to trigger custom events at the browser.
This example demonstrates how to use `HX-Trigger` response header to trigger custom events at the browser.

* [HX-Trigger-2]

This example demonstrates how to use `HX-Trigger` response header to trigger custom events with JSON payload at the browser.
24 changes: 24 additions & 0 deletions projects/htmx/header-hx-trigger-2/.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"
}
130 changes: 130 additions & 0 deletions projects/htmx/header-hx-trigger-2/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
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>HX-Trigger</h1>
<p>Click on the below links to see the response.</p>
<ul>
<li hx-get="/htmx">GET</li>
<li hx-post="/htmx">POST</li>
<li hx-put="/htmx">PUT</li>
<li hx-patch="/htmx">PATCH</li>
<li hx-delete="/htmx">DELETE</li>
</ul>
<script src="https://unpkg.com/[email protected]" integrity="sha384-wS5l5IKJBvK6sPTKa2WZ1js3d947pvWXbPJ1OmWfEuxLgeHcEbjUUA5i9V5ZkpCw" crossorigin="anonymous"></script>
<script>
document.addEventListener("show-me", (evt) => {
alert(evt.detail.message);
});
document.addEventListener("htmx:configRequest", (evt) => {
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.IsHtmx() is false)
return Results.Content("");

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, HttpResponse response) =>
{
response.Htmx(x =>
{
x.WithTrigger("show-me", new { message = "GET request" });
});

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

htmx.MapPost("/", (HttpRequest request, HttpResponse response) =>
{
response.Htmx(x =>
{
x.WithTrigger("show-me", new { message = "POST request" });
});

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

htmx.MapDelete("/", (HttpRequest request, HttpResponse response) =>
{
response.Htmx(x =>
{
x.WithTrigger("show-me", new { message = "DELETE request" });
});

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

htmx.MapPut("/", (HttpRequest request, HttpResponse response) =>
{
response.Htmx(x =>
{
x.WithTrigger("show-me", new { message = "PUT request" });
});

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

htmx.MapPatch("/", (HttpRequest request, HttpResponse response) =>
{
response.Htmx(x =>
{
x.WithTrigger("show-me", new { message = "PATCH request" });
});

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

app.Run();
17 changes: 17 additions & 0 deletions projects/htmx/header-hx-trigger-2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# HX-Trigger Response Headers with JSON payload

This example demonstrates the usage of `HX-Trigger` response header to emit custom events with JSON payload at the client([doc](https://htmx.org/headers/hx-trigger/)).

We are using the nice utilities provided by the excellent [Htmx](https://www.nuget.org/packages/Htmx) package.

```csharp
htmx.MapGet("/", (HttpRequest request, HttpResponse response) =>
{
response.Htmx(x =>
{
x.WithTrigger("show-me", new { message = "GET request" });
});

return Results.Content($"GET => {DateTime.UtcNow}");
});
```
9 changes: 9 additions & 0 deletions projects/htmx/header-hx-trigger-2/header-hx-trigger-2.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>
25 changes: 25 additions & 0 deletions projects/htmx/header-hx-trigger-2/header-hx-trigger-2.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.002.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "header-hx-trigger-2", "header-hx-trigger-2.csproj", "{A156188D-B2EB-4287-BCBB-18F172DAD7CB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A156188D-B2EB-4287-BCBB-18F172DAD7CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A156188D-B2EB-4287-BCBB-18F172DAD7CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A156188D-B2EB-4287-BCBB-18F172DAD7CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A156188D-B2EB-4287-BCBB-18F172DAD7CB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB9EBD12-9613-423B-8586-FAFF6B28005A}
EndGlobalSection
EndGlobal

0 comments on commit c4ce345

Please sign in to comment.