This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Zeigt Toast und Swapping-Inhalte mit HTMX und ASPM..NET Core.).
Saturday, 12 April 2025
Einleitung
HTMX ist eine großartige Bibliothek, um Ihre Web-Anwendungen dynamischer und responsiver zu machen.In diesem Beitrag zeigen Sie I,.I'.ll, wie man HTML verwendet, um eine Toast-Benachrichtigung anzuzeigen und Inhalte auf der Seite auszutauschen.
Eine der Begrenzungen von ' im Standard HTMX nicht OOB-SwapsDas ist, dass Sie in der Regel nur ein einzelnes Stück Inhalt aus dem hinteren Ende getauscht haben. HX-Trigger Kopfzeilen und ein wenig Javascript.
HINWEIS:-Sie können verwenden hx-swap-oob um zwei verschiedene Inhalt Elemente, aber dies ist ein bisschen komplexer und nicht so einfach zu verwenden für einige JavaScripty-Sache .
TOAST
I'-ve verwendet diese eine Variante dieses einfachen Toast Benachrichtigungssystem für eine Weile jetztEs ist eine einfache Funktion, die eine Nachricht annimmt.,... Dauer:,... und Typ: (...Erfolgsfehler...,... Warnung:MSC7... und zeigt eine Toast-Benachrichtigung auf der Seite: MSC8.
Diese neueste Version von ' hat noch etwas mehr Bling um Icons, Animationen usw.
Das Javascript
// HTMX toast notification
// Simple HTMX toast handler for use with hx-on::after-request
window.showToast = (message, duration = 3000, type = 'info') => {
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toast-message');
const toastText = document.getElementById('toast-text');
const toastIcon = document.getElementById('toast-icon');
// Reset classes
toastMessage.className = 'alert shadow-lg gap-2 transition-all duration-300 ease-in-out cursor-pointer';
toastIcon.className = 'bx text-2xl';
// Add DaisyUI alert type
const alertClass = `alert-${type}`;
toastMessage.classList.add(alertClass);
// Add icon class
const iconMap = {
success: 'bx-check-circle',
error: 'bx-error-circle',
warning: 'bx-error',
info: 'bx-info-circle'
};
const iconClass = iconMap[type] || 'bx-bell';
toastIcon.classList.add(iconClass);
// Set the message
toastText.textContent = message;
// Add slide-in animation
toastMessage.classList.add('animate-slide-in');
toast.classList.remove('hidden');
// Allow click to dismiss
toastMessage.onclick = () => hideToast();
// Auto-dismiss
clearTimeout(window.toastTimeout);
window.toastTimeout = setTimeout(() => hideToast(), duration);
function hideToast() {
toastMessage.classList.remove('animate-slide-in');
toastMessage.classList.add('animate-fade-out');
toastMessage.onclick = null;
toastMessage.addEventListener('animationend', () => {
toast.classList.add('hidden');
toastMessage.classList.remove('animate-fade-out');
}, { once: true });
}
};
Dies benutzt ein kleines HTML-Snippet, das ich in meinem _Layout-Datei .Cshtml mit meinem bevorzugten Tailwind CSS .& .DaisyUI .). .Beachten Sie, dass die .SK4 .class conserving block . ' . am Ende ist es ein kleiner Trick, um sicherzustellen, dass der Klassen in der endgültigen HTML-Ausgabe erhalten bleiben ?. . Dies ist wirklich für meine Rückwärtswind Setup wie ich nur auf cshtml.
<div
id="toast"
class="toast toast-bottom fixed z-50 hidden w-full md:w-auto max-w-sm right-4 bottom-4"
>
<div
id="toast-message"
class="alert shadow-lg gap-2 transition-all duration-300 ease-in-out cursor-pointer"
>
<i id="toast-icon" class="bx text-2xl"></i>
<span id="toast-text">Notification message</span>
</div>
</div>
<!-- class-preserving dummy block -->
<div class="hidden">
<div class="alert alert-success alert-error alert-warning alert-info"></div>
<i class="bx bx-check-circle bx-error-circle bx-error bx-info-circle bx-bell"></i>
<div class="animate-slide-in animate-fade-out"></div>
</div>
Rückenwind
Hier definiere ich, welche Dateien zu '-tree---shake-'- sowie einige Animationsklassen der Toast verwendet
const defaultTheme = require("tailwindcss/defaultTheme");
module.exports = {
content: ["./Views/**/*.cshtml", "./Areas/**/*.cshtml"],
safelist: ["dark"],
darkMode: "class",
theme: {
extend: {
keyframes: {
'slide-in': {
'0%': { opacity: 0, transform: 'translateY(20px)' },
'100%': { opacity: 1, transform: 'translateY(0)' },
},
'fade-out': {
'0%': { opacity: 1 },
'100%': { opacity: 0 },
},
},
animation: {
'slide-in': 'slide-in 0.3s ease-out',
'fade-out': 'fade-out 0.5s ease-in forwards',
},
},
plugins: [require("daisyui")],
};
Ausgelöst
Das Geheimnis, dass dies alles funktioniert ist die Verwendung der HTMX Trigger-Headerfunktionalität.
Jetzt würden Sie normalerweise Definieren Sie dies in Ihrem aktuellen html-Rasurcode:
<div hx-get="/clicked" hx-trigger="click[ctrlKey]">Control Click Me</div>
Oder Sie können es in einem nach Anfrage Ereignis definieren. Also tun Sie etwas, dann löst es ein neues Ereignis aus.
<button
hx-get="/api/do-something"
hx-swap="none"
hx-on::afterRequest="window.showToast('API call complete!', 3000, 'success')"
class="btn btn-primary"
>
Do Something
</button>
Dies ist praktisch, wenn du einfach etwas tun willst dann zeigen Sie es an.'s getan... aber in meinem Fall möchte ich einige Inhalte austauschen und einen Toast anzeigen.
Response.Headers.Append("HX-Trigger", JsonSerializer.Serialize(new
{
showToast = new
{
toast = result.Message,
issuccess = result.Success
}
}));
In meinem Fall ist mein Auslöser benannt showToast und ich übergebe eine Nachricht und eine Erfolgsflagge, also i my JS Ich habe einen Event-Hörer für dieses Ereignis definiert. showToast Funktion und übergeben in der Nachricht und Erfolg Flagge
// Handles HX-Trigger: { "showToast": { "toast": "...", "issuccess": true } }
document.body.addEventListener("showToast", (event) => {
const { toast, issuccess } = event.detail || {};
const type = issuccess === false ? 'error' : 'success';
showToast(toast || 'Done!', 3000, type);
});
ASP-.-NET
Also warum verwende ich diese ,?' Nun in einem aktuellen Arbeitsprojekt wollte ich einige Maßnahmen auf einen Benutzer in einer Tabelle zeigen , um eine Toast-Benachrichtigung anzeigen und tauschen Sie den Inhalt der Benutzerzeile mit dem neuen Inhalt

Wie Sie sehen können, habe ich eine BUNCH von Schaltflächen welche '-do Sachen an den Benutzer zeigen Ich wollte einen Toast Benachrichtigung und tauschen Sie den Inhalt der Benutzerzeile mit dem neuen Inhalt .
So in meinem kontrollierten Ich habe eine einfache '-Schaltung, die den Action-Namen nimmt.,... tut Sachen dann gibt das neue Request-Ergebnis zurück.
private async Task ApplyAction(string email, string useraction)
{
if (!string.IsNullOrWhiteSpace(useraction) &&
Enum.TryParse<UserActionType>(useraction, true, out var parsedAction))
{
RequestResult result;
switch (parsedAction)
{
case UserActionType.FlipRoles:
result = await userActionService.FlipRestaurantPermissions(email);
break;
case UserActionType.UnflipRoles:
result = await userActionService.UnFlipRestaurantPermissions(email);
break;
case UserActionType.Enable2FA:
result = await userActionService.ToggleMFA(email, true);
break;
case UserActionType.Disable2FA:
result = await userActionService.ToggleMFA(email, false);
break;~~~~
case UserActionType.RevokeTokens:
result = await userActionService.RevokeTokens(email);
break;
case UserActionType.Lock:
result = await userActionService.Lock(email);
break;
case UserActionType.Unlock:
result = await userActionService.Unlock(email);
break;
case UserActionType.Nuke:
result = await userActionService.Nuke(email);
break;
case UserActionType.Disable:
result = await userActionService.DisableUser(email);
break;
case UserActionType.Enable:
result = await userActionService.EnableUser(email);
break;
case UserActionType.ResetPassword:
result = await userActionService.ChangePassword(email);
break;
case UserActionType.SendResetEmail:
result = await userActionService.SendResetEmail(email);
break;
default:
result = new RequestResult(false, "Unknown action");
break;
}
Response.Headers.Append("HX-Trigger", JsonSerializer.Serialize(new
{
showToast = new
{
toast = result.Message,
issuccess = result.Success
}
}));
}
}
Sie können sehen, dass ich auch die HX-Trigger header to the response. Dies ist ein JSON-Objekt mit dem showToast Schlüssel und ein Wert eines Objekts mit dem toast und issuccess Schlüssel ,. , die toast Schlüssel ist die Nachricht, um in der Toast-Benachrichtigung und der issuccess Schlüssel ist ein Boolean, der anzeigt, ob die Aktion erfolgreich war oder nicht.
Dann in der _Row teilweise habe ich die HX-Attribute, um die Aktion auszulösen
<!-- Revoke Login Tokens -->
<button class="btn btn-xs btn-error border whitespace-normal text-wrap tooltip tooltip-left" data-tip="Revoke login tokens"
hx-get hx-indicator="#loading-modal" hx-target="closest tr" hx-swap="outerHTML"
hx-action="Row" hx-controller="Users"
hx-route-email="@user.Email" hx-route-useraction="@UserActionType.RevokeTokens"
hx-confirm="Are you sure you want to revoke the login tokens for this user?">
<i class="bx bx-power-off"></i> Revoke
</button>
Du siehst, ich benutze das Ziel. closest tr Um die gesamte Zeile mit dem neuen Inhalt zu tauschen, ist dies ein einfacher Weg, um den Inhalt der Zeile zu aktualisieren, ohne eine ganze Seite refresh-.
Teilansicht
Dies ist wirklich sehr einfach und eine großartige Technik für ASP-.-NET Core mit HTMX-MSC1
Sie können optional HTMX-.-Net verwendens Bitten Sie .-IsHtmx-`- hier, aber in diesem Fall benutze ich das nur von einem HTMX Callback.
[Route("row")]
public async Task<IActionResult> Row(string email, string? useraction = null)
{
if(!string.IsNullOrEmpty(useraction))
await ApplyAction(email, useraction);
var userRow = await userViewService.GetSingleUserViewModel(email);
return PartialView("_Row", userRow);
}
In diesem Fall die Teilansicht _Row ist eine einfache Tabellenzeile mit den Benutzerinformationen und den Schaltflächen, um die Aktionen durchzuführen
Zusätzliche HTMX-Funktionen
Ich benutze auch ein paar von mehr HTMX-Funktionen, um die Benutzererfahrung besser zu machen
Laden
Ich benutze auch eine einfache loading modal um anzuzeigen, dass die Anfrage im Gange ist..- Dies ist eine einfache Möglichkeit, dem Benutzer zu zeigen, dass etwas im Hintergrund geschieht..-
<div id="loading-modal" class="modal htmx-indicator">
<div
class="modal-box flex flex-col items-center justify-center bg-base-200 border border-base-300 shadow-xl rounded-xl text-base-content dark text-center ">
<div class="flex flex-col items-center space-y-4">
<h2 class="text-lg font-semibold tracking-wide">Loading...</h2>
<span class="loading loading-dots loading-xl text-4xl text-stone-200"></span>
</div>
</div>
</div>
Bestätigen
Ich benutze auch die hx-confirm Attribut, um einen Bestätigungsdialog zu zeigen, bevor die Aktion ausgeführt wird..-Dies ist ein einfacher Weg, um sicherzustellen, dass der Benutzer wirklich die Aktion ausführen will. SüßAlert-2 um einen Bestätigungsdialog anzuzeigen
Nun, wenn du DON-'-T tun Sie dies... HTMX funktioniert noch, aber es verwendet den Standard-Browser 'confirm" -Dialog, der ein bisschen Jarring für den Benutzer sein kann.
// HTMX confirm with SweetAlert2
window.addEventListener('htmx:confirm', (e) => {
const message = e.detail.question;
if (!message) return;
e.preventDefault();
Swal.fire({
title: 'Please confirm',
text: message,
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Yes',
cancelButtonText: 'Cancel',
theme: 'dark',
}).then(({ isConfirmed }) => {
if (isConfirmed) e.detail.issueRequest(true);
});
});
Schlussfolgerung
Dies ist ein einfacher Weg, um HTMX zu verwenden, um eine Toast-Benachrichtigung und Swap-Inhalte auf der Seite zeigen Dies ist eine gute Möglichkeit, Ihre Web-Anwendungen dynamischer und responsiver zu machen