renerick / htmx-signalr Goto Github PK
View Code? Open in Web Editor NEWhtmx extension for interacting with ASP.NET Core SignalR connections directly from HTML
License: MIT License
htmx extension for interacting with ASP.NET Core SignalR connections directly from HTML
License: MIT License
I suspect this is likely something to be addressed via an update to the readme rather than a feature request. I have a server side method that takes an int parameter. I'm using signalr-send on a form element and getting the value for that parameter from a hidden input. Until I enabled debug signalr logging I didn't understand why the breakpoint in my server code was never being hit (and the server method never being executed). It looks like all params get sent over as strings, so the server side stuff needs to only take strings, unless I've overlooked something.
Changing my params in the server code to strings and just parsing the int out on that side works just fine, but it wasn't obvious at first what was going on.
Hi Renerick,
I try to use your solution in asp.net core mvc. the .net framework is .net 8 standard version.
However, even I copied exactly everything from your demo, signalR test hub is not triggered.
Can you please give me some advice?
Thanks.
Terrence
https://news.ycombinator.com/item?id=40709769
Can swap out to use it
Moving issue here from bigskysoftware/htmx#1419
I'm using htmx 1.9.2
with htmx-signalr and it fails on this line https://github.com/bigskysoftware/htmx/blob/990cdd61a110bd497cb50d2286407ac6b7b64183/src/htmx.js#L948 with
023-04-29T12:36:15.320Z] Error: A callback for the method 'component-update' threw error 'TypeError: Cannot read properties of null (reading 'firstChild')'.
If element received via signalr had hx-swap-oob="outerHTML"
and some parent of the target had hx-swap="outerHTML"
For example with such layout:
<div hx-ext="signalr" signalr-connect="/hub" >
<div id="second-level" hx-swap="outerHTML">
<div id="component" signalr-subscribe="component-update" hx-target="this" > <div/>
<div/>
<div/>
When extension receives
<div id="component" signalr-subscribe="component-update" hx-target="this" hx-swap-oob="outerHTML" >Some new content here<div/>
It replaces the content correctly, but then throws above exception after which any further updates would be ignored.
The workaround is to set hx-swap="innerhtml"
on the target node in the original layout [1], so call to getSwapSpecification
here returns innerhtml
.
[1] Workaround
<div hx-ext="signalr" signalr-connect="/hub" >
<div id="second-level" hx-swap="outerHTML">
<div id="component" signalr-subscribe="component-update" hx-target="this" hx-swap="innerhtml"> <div/>
<div/>
<div/>
I'm using signalr-subscribe for chat-like functionality on a div with overflow-y: auto and hx-swap beforeend so that new messages have their markup appended to the end of the div. I'd like to automatically scroll the new content into view. This doesn't seem to work.
I think this is the same issue as bigskysoftware/htmx#784 which references bigskysoftware/htmx#255 but I wasn't sure if you wanted to track this separately or not.
I'm pretty sure I can work around this (maybe a load handler in the new p element sent by the server that does scrolling). I don't think handling htmx:signalr:message would work because that happens before - maybe htmx:afterswap or something.
First, let me thank you for taking time creating this extension, especially when the use case is so narrow (it is rare for signal r to be used outside of dotnet, ant htmx is for sure not the most popular technologies out there)
While trying to make sense of the event emitted as was not been able to understand why I 'htmx:signalr:reconnecting' nor 'htmx:signalr:reconnected' were being triggered (made sense of this after reading the code) I realized that the connection errors on the start are not being managed as there is not catch block for the start promise. Would you consider creating an additional event for when a connection error happens?
Here is a little snippet of what I did (note I put bunch of console.log to understand when events are triggered) that can be used as reference
// Create a new HubConnection and event handlers
/** @type {HubConnection} */
var hubConnection = htmx.createHubConnection(signalrHubUrl);
hubConnection.onreconnecting(function (error) {
console.log('Triggering htmx:signalr:reconnecting from onreconnecting');
api.triggerEvent(hubElt, 'htmx:signalr:reconnecting', { error: error });
});
hubConnection.onreconnected(function (connectionId) {
console.log('Triggering htmx:signalr:reconnected from onreconnected');
api.triggerEvent(hubElt, 'htmx:signalr:reconnected', { connectionId: connectionId });
});
hubConnection.onclose(function (error) {
console.log('Triggering htmx:signalr:close from onclose');
api.triggerEvent(hubElt, 'htmx:signalr:close', { error: error });
});
hubConnection.start().then(function () {
console.log('Triggering htmx:signalr:start from start');
api.triggerEvent(hubElt, 'htmx:signalr:start', { connectionId: hubConnection.connectionId })
}).catch(function(ex) {
console.log(ex);
console.log('Triggering htmx:signalr:connection-error from start error');
api.triggerEvent(hubElt, 'htmx:signalr:connection-error', { message:ex.message, errorType:ex.errorType })
});
I would like htmx-signalr to handle and expose the SignalR hub's onreconnecting
and onreconnected
methods. In case of intermittent connectivity to the hub, it is often desirable to signal the user that there's an issue (such as "reconnecting to the server, please wait").
In the spirit of htmx, it could be done declaratively, such as:
<div id="chat-room-list"
hx-ext="signalr,client-side-templates"
signalr-connect="/chatroomlist"
signalr-subscribe="chat-room-list-change"
signalr-reconnect-target="reconnect-div" <!-- <<< This one -->
mustache-array-template="chat-room-list-entry">
Connecting...
</div>
<div id="reconnect-div">Reconnecting...</div> <!-- <<< This one -->
htmx-signalr would show and hide the target as required.
Also, the 2 attributes - onreconnecting
and onreconnected
could be used to attach JavaScript handlers, just in case further customizations are needed (onreconnecting could pass the error?: Error
from the SignalR's event).
Also, please document that it is possible to provide custom htmx.createHubConnection
method that can use a customized reconnection policy. That was a pleasant surprise to me.
Thanks.
Maybe we can add support for htmx headers by sending object instead of string
public class HtmxHeaders //This will be added to library with fluent api or sth
{
[JsonPropertyName("HX-Target")]
public string Target { get; set; }
[JsonPropertyName("HX-Push-Url")]
public string PushUrl { get; set; }
}
var headers = new HtmxHeaders
{
Target = "game",
PushUrl = $"game/{log.GameId.ToString()}"
};
await hubContext.Clients
.Group(log.GameId.Value)
.SendAsync("game-started", message, new { HEADERS = headers }, ct);
this code will send
{
"type": 1,
"target": "game-started",
"arguments": [
"<div>Something</div>",
{
"headers": {
"HX-Target": "game",
"HX-Push-Url": "game/c-BsMYCRPQ"
}
}
]
}
Question is if this will break something and if this will be hard to handle in js?
For comparison this is message sent from the client to server
{
"arguments": [
{
"playerId": "Walter.Bednar",
"HEADERS": {
"HX-Request": "true",
"HX-Trigger": null,
"HX-Trigger-Name": null,
"HX-Target": "game",
"HX-Current-URL": "http://192.168.0.10:5104/"
}
}
],
"target": "newGame",
"type": 1
}
When using signalr-send on a form element, after the send message (on form submit), the form isn't reset. This is different from how default htmx works when applying an hx-post attribute to it.
I didn't see anything in your source that handles this specially, but I'm pretty new to all of this so I might have missed it.
Worst case I know I can hook the afterSend event and just write some script to clear the form, but I wasn't sure if you were intending to have this work just like hx-post.
Thanks!
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>
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.