add docs for SSE
This commit is contained in:
parent
e235aa58ba
commit
7503e1b2c1
3 changed files with 72 additions and 13 deletions
|
|
@ -16,10 +16,7 @@ func ChatRoom(ctx *h.RequestContext) *h.Page {
|
||||||
return h.NewPage(
|
return h.NewPage(
|
||||||
RootPage(
|
RootPage(
|
||||||
h.Div(
|
h.Div(
|
||||||
h.JoinExtensions(
|
h.TriggerChildren(),
|
||||||
h.TriggerChildren(),
|
|
||||||
h.HxExtension("ws"),
|
|
||||||
),
|
|
||||||
|
|
||||||
h.Attribute("sse-connect", fmt.Sprintf("/ws/chat/%s", roomId)),
|
h.Attribute("sse-connect", fmt.Sprintf("/ws/chat/%s", roomId)),
|
||||||
|
|
||||||
|
|
@ -143,10 +140,6 @@ func MessageInput() *h.Element {
|
||||||
return h.Input("text",
|
return h.Input("text",
|
||||||
h.Id("message-input"),
|
h.Id("message-input"),
|
||||||
h.Required(),
|
h.Required(),
|
||||||
h.Class("p-4 rounded-md border border-slate-200 w-full focus:outline-none focus:ring focus:ring-slate-200"),
|
|
||||||
h.Name("message"),
|
|
||||||
h.MaxLength(1000),
|
|
||||||
h.Placeholder("Type a message..."),
|
|
||||||
h.HxAfterSseMessage(
|
h.HxAfterSseMessage(
|
||||||
js.SetValue(""),
|
js.SetValue(""),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
65
htmgo-site/md/docs/6_pushing_data/1_server_sent_events.md
Normal file
65
htmgo-site/md/docs/6_pushing_data/1_server_sent_events.md
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
**Server Sent Events (SSE)**
|
||||||
|
|
||||||
|
htmgo supports server-sent events (SSE) out of the box.
|
||||||
|
This allows you to push data from the server to the client in real-time.
|
||||||
|
|
||||||
|
Example of this can be found in the [chat-app](https://github.com/maddalax/htmgo/tree/master/examples/chat) example.
|
||||||
|
Demo: https://chat-example.htmgo.dev
|
||||||
|
|
||||||
|
## How it works ##
|
||||||
|
1. The client sends a request to the server to establish a connection.
|
||||||
|
2. The server holds the connection open and sends data (in our case, most likely elements) to the client whenever there is new data to send.
|
||||||
|
3. The htmgo SSE extension uses https://htmx.org/attributes/hx-swap-oob/ to swap out the elements that the server sends.
|
||||||
|
|
||||||
|
|
||||||
|
**Note**: SSE is **unidirectional** (the server can only send data to the client).
|
||||||
|
For the client to send data to the server, normal xhr behavior should be used (form submission, triggers, etc).
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
1. Add the SSE connection attribute and the path to the handler that will handle the connection.
|
||||||
|
|
||||||
|
```go
|
||||||
|
h.Attribute("sse-connect", fmt.Sprintf("/chat/%s", roomId))
|
||||||
|
```
|
||||||
|
|
||||||
|
The following **Event Handlers** can be used to react to SSE connections.
|
||||||
|
```go
|
||||||
|
h.HxOnSseOpen
|
||||||
|
h.HxBeforeSseMessage
|
||||||
|
h.HxAfterSseMessage
|
||||||
|
h.HxOnSseError
|
||||||
|
h.HxOnSseClose
|
||||||
|
h.HxOnSseConnecting
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example:** Adding an event listener handle SSE errors.
|
||||||
|
|
||||||
|
```go
|
||||||
|
h.HxOnSseError(
|
||||||
|
js.EvalJs(fmt.Sprintf(`
|
||||||
|
const reason = e.detail.event.data
|
||||||
|
if(['invalid room', 'no session', 'invalid user'].includes(reason)) {
|
||||||
|
window.location.href = '/?roomId=%s';
|
||||||
|
} else if(e.detail.event.code === 1011) {
|
||||||
|
window.location.reload()
|
||||||
|
} else if (e.detail.event.code === 1008 || e.detail.event.code === 1006) {
|
||||||
|
window.location.href = '/?roomId=%s';
|
||||||
|
} else {
|
||||||
|
console.error('Connection closed:', e.detail.event)
|
||||||
|
}
|
||||||
|
`, roomId, roomId)),
|
||||||
|
),
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example:** Clearing the input field after sending a message.
|
||||||
|
```go
|
||||||
|
func MessageInput() *h.Element {
|
||||||
|
return h.Input("text",
|
||||||
|
h.Id("message-input"),
|
||||||
|
h.Required(),
|
||||||
|
h.HxAfterSseMessage(
|
||||||
|
js.SetValue(""),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
@ -15,10 +15,11 @@ type Example struct {
|
||||||
|
|
||||||
var examples = []Example{
|
var examples = []Example{
|
||||||
{
|
{
|
||||||
Title: "Chat App Example",
|
Title: "Chat App Example",
|
||||||
Github: "https://github.com/maddalax/htmgo/tree/master/examples/chat",
|
Github: "https://github.com/maddalax/htmgo/tree/master/examples/chat",
|
||||||
Demo: "https://chat-example.htmgo.dev",
|
Description: "A simple chat application built with htmgo using SSE for real-time updates",
|
||||||
Image: "public/chat-example.jpg",
|
Demo: "https://chat-example.htmgo.dev",
|
||||||
|
Image: "public/chat-example.jpg",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Todo List MVC",
|
Title: "Todo List MVC",
|
||||||
|
|
@ -73,7 +74,7 @@ func ExamplesPage(ctx *h.RequestContext) *h.Page {
|
||||||
|
|
||||||
func ExampleCards() *h.Element {
|
func ExampleCards() *h.Element {
|
||||||
return h.Div(
|
return h.Div(
|
||||||
h.Class("prose-h2:my-1 prose-img:my-1 grid grid-cols-1 md:grid-cols-3 gap-6 text-center pb-8"), // Using grid for 3-column layout
|
h.Class("prose-h2:my-1 prose-img:my-1 grid grid-cols-1 md:grid-cols-2 gap-6 text-center pb-8"), // Using grid for 3-column layout
|
||||||
h.List(examples, func(example Example, index int) *h.Element {
|
h.List(examples, func(example Example, index int) *h.Element {
|
||||||
return h.Div(
|
return h.Div(
|
||||||
h.Class("border border-gray-200 shadow-sm rounded-md px-4 pb-4 bg-neutral-100"), // Removed specific width, handled by grid
|
h.Class("border border-gray-200 shadow-sm rounded-md px-4 pb-4 bg-neutral-100"), // Removed specific width, handled by grid
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue