# Zeigt Toast und Swapping-Inhalte mit HTMX und ASPM..NET Core.).

<datetime class="hidden">2025-04-12T13:33</datetime>

<!--category-- ASP.NET Core, HTMX -->
# 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-Swaps](https://htmx.org/attributes/hx-swap-oob/)Das 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`](https://htmx.org/attributes/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 .**

[TOC]

# TOAST

I'-ve verwendet diese eine Variante dieses einfachen Toast Benachrichtigungssystem [für eine Weile jetzt](https://www.mostlylucid.net/blog/acopybuttonforhightlightjs#showtoast-function)Es 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

```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`.

```html
<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

```javascript
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](https://htmx.org/headers/hx-trigger/).

Jetzt würden Sie normalerweise [Definieren Sie dies in Ihrem aktuellen html-Rasurcode](https://htmx.org/attributes/hx-trigger/):

```html
<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.

```html
<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.

```csharp
            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

```javascript
// 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

![userrow.png](userrow.png)

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.

```csharp
    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

```html
                     <!-- 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 verwenden`s `Bitten Sie .-IsHtmx-`- hier, aber in diesem Fall benutze ich das nur von einem HTMX Callback.

```csharp
    [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..-

```html
<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](https://sweetalert2.github.io/) 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.

```javascript
// 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