Renerick / htmx-signalr

htmx extension for interacting with ASP.NET Core SignalR connections directly from HTML
MIT License
45 stars 5 forks source link

Send get request after signalR event #8

Closed Nairda015 closed 1 year ago

Nairda015 commented 1 year ago

What I'm doing wrong? Hub is mapped and I can confirm that messages from the websocket are received in dev tools

https://htmx.org/extensions/server-sent-events/

public class LobbyHub(LobbyQueue lobbyQueue) : Hub
{
    public override Task OnConnectedAsync()
    {
        lobbyQueue.Add(Context.ConnectionId, null);
        Clients.All.SendAsync("lobby-update", $"Player added {Context.ConnectionId}");
        return base.OnConnectedAsync();
    }
}   
<div hx-ext="signalr" signalr-connect="/lobby-hub">
    <table>
        <thead>
        <tr>
            <th>Player Id</th>
            <th>Game Id</th>
        </tr>
        </thead>
        <tbody hx-get="/refresh-lobby" hx-trigger="sse:lobby-update">

        </tbody>
    </table>
</div>
Nairda015 commented 1 year ago

So I found workaround for now you can return message like this with load trigger

var message = $"""<div class="hidden" hx-get="/refresh-board" hx-trigger="load" hx-swap="outerHTML" hx-target="#board"></div>""";
        await hubContext.Clients
            .Group(log.GameId.Value)
            .SendAsync("game-started", message, ct);

it is important to add empty subscriber

<div id="game" hx-ext="signalr" signalr-connect="/game-hub">
    ...

    <div id="new-game-hack" signalr-subscribe="game-started"></div>
</div>
Renerick commented 1 year ago

Server-Sent Events are a separate technology and htmx extension, independent of WebSockets and SignalR extensions. The feature you highlighted (using sse: prefixed events specifically) is only supported by SSE extension and won't work with WS or SignalR extensions.

The workaround you provided is necessitated by the design of SignalR itself, that is, you have to explicitly subscribe to desired events ^1 and by the goal of mirroring the way htmx's official WebSocket extension works by receiving HTML strings. Ideally, you would be able to pass HX-Trigger header in the message from the server, but it's not possible due to this design constraints atm.

If you don't want to pass unnecessary html in the message, you should be able to utilize this extension's events, but you would have to use signalr-subscribe attribute regardless

<div id="new-game-hack" signalr-subscribe="game-started" hx-get="/refresh-board" hx-trigger="htmx:singnalr:message" hx-swap="outerHTML" hx-target="#board"></div>
Renerick commented 1 year ago

I'm going to close the issue as there is nothing to fix really. Feel free to reopen if you have any other questions or suggestions

Nairda015 commented 8 months ago

Maybe I don't understand this fully. Is this possible to send notification without message only to trigger get request from the client?

await hubContext.Clients.All.SendAsync("lobby-updated", stoppingToken);
<tbody
    id="lobby-table-body"
    signalr-subscribe="lobby-updated"
    hx-get="/refresh-lobby"
    hx-trigger="load, htmx:singnalr:message">
</tbody>
Renerick commented 8 months ago

hmm, this should work

Renerick commented 8 months ago

you have a typo

- htmx:singnalr:message
+ htmx:signalr:message
Nairda015 commented 8 months ago

Thanks!

In the code there is no check if message is empty and internally htmx throw so maybe we can add

if (!message) return; 

around line 203

Renerick commented 8 months ago

Agree, I'll do that in a bit

Renerick commented 8 months ago

See https://github.com/Renerick/htmx-signalr/commit/e3e5b81ec35ed17f085ac87172ba9b4812832087