Add load more how to [deploy-site]
This commit is contained in:
parent
d60f326230
commit
bebd836f45
|
@ -23,6 +23,7 @@ func setupHowTos(ctx context.Context, router chi.Router) error {
|
|||
Label: "How Tos",
|
||||
Links: []*SidebarLink{
|
||||
{ID: "how_to_bind_keydown_events_to_specific_keys"},
|
||||
{ID: "how_to_load_more_list_items"},
|
||||
{ID: "how_to_poll_the_backend_at_regular_intervals"},
|
||||
{ID: "how_to_redirect_the_page_from_the_backend"},
|
||||
},
|
||||
|
@ -76,8 +77,9 @@ func setupHowTos(ctx context.Context, router chi.Router) error {
|
|||
})
|
||||
|
||||
if err := errors.Join(
|
||||
setupHowTosLoadMore(howTosRouter),
|
||||
setupHowTosPolling(howTosRouter),
|
||||
setupHowTosRedirects(howTosRouter),
|
||||
setupHowTosRedirect(howTosRouter),
|
||||
); err != nil {
|
||||
panic(fmt.Sprintf("error setting up examples routes: %s", err))
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package site
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
datastar "github.com/starfederation/datastar/sdk/go"
|
||||
)
|
||||
|
||||
type OffsetSignals struct {
|
||||
Offset int `json:"offset"`
|
||||
}
|
||||
|
||||
func setupHowTosLoadMore(howTosRedirect chi.Router) error {
|
||||
|
||||
howTosRedirect.Route("/load_more/data", func(dataRouter chi.Router) {
|
||||
|
||||
dataRouter.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
signals := &OffsetSignals{}
|
||||
if err := datastar.ReadSignals(r, signals); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
}
|
||||
|
||||
max := 5
|
||||
limit := 1
|
||||
offset := signals.Offset
|
||||
|
||||
sse := datastar.NewSSE(w, r)
|
||||
|
||||
if offset < max {
|
||||
newOffset := offset + limit
|
||||
sse.MergeFragments(fmt.Sprintf(`<div class="text-primary font-bold">Item %d</div>`, newOffset),
|
||||
datastar.WithSelectorID("list"),
|
||||
datastar.WithMergeMode(datastar.FragmentMergeModeAppend),
|
||||
)
|
||||
if newOffset < max {
|
||||
sse.MergeSignals([]byte(fmt.Sprintf(`{offset: %d}`, newOffset)))
|
||||
} else {
|
||||
sse.RemoveFragments(`#load-more`)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
|
@ -8,7 +8,7 @@ import (
|
|||
datastar "github.com/starfederation/datastar/sdk/go"
|
||||
)
|
||||
|
||||
func setupHowTosRedirects(howTosRedirect chi.Router) error {
|
||||
func setupHowTosRedirect(howTosRedirect chi.Router) error {
|
||||
|
||||
howTosRedirect.Route("/redirect/data", func(dataRouter chi.Router) {
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
datastar "github.com/starfederation/datastar/sdk/go"
|
||||
)
|
||||
|
||||
type OffsetSignals struct {
|
||||
Offset int `json:"offset"`
|
||||
}
|
||||
|
||||
signals := &OffsetSignals{}
|
||||
if err := datastar.ReadSignals(r, signals); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
}
|
||||
|
||||
max := 5
|
||||
limit := 1
|
||||
offset := signals.Offset
|
||||
|
||||
sse := datastar.NewSSE(w, r)
|
||||
|
||||
if offset < max {
|
||||
newOffset := offset + limit
|
||||
sse.MergeFragments(fmt.Sprintf(`<div>Item %d</div>`, newOffset),
|
||||
datastar.WithSelectorID("list"),
|
||||
datastar.WithMergeMode(datastar.FragmentMergeModeAppend),
|
||||
)
|
||||
if newOffset < max {
|
||||
sse.MergeSignals([]byte(fmt.Sprintf(`{offset: %d}`, newOffset)))
|
||||
} else {
|
||||
sse.RemoveFragments(`#load-more`)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
use starfederation\datastar\enums\FragmentMergeMode;
|
||||
use starfederation\datastar\ServerSentEventGenerator;
|
||||
|
||||
$signals = ServerSentEventGenerator::readSignals();
|
||||
|
||||
$max = 5;
|
||||
$limit = 1;
|
||||
$offset = $signals['offset'] ?? 1;
|
||||
|
||||
$sse = new ServerSentEventGenerator();
|
||||
|
||||
if ($offset < $max) {
|
||||
$newOffset = $offset + $limit;
|
||||
$sse->mergeFragments(`<div>Item $newOffset</div>`, [
|
||||
'selector' => '#list',
|
||||
'mergeMode' => FragmentMergeMode::Append,
|
||||
]);
|
||||
if (newOffset < $max) {
|
||||
$sse->mergeSignals(['offset' => $newOffset]);
|
||||
} else {
|
||||
$sse->removeFragments('#load-more');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
# How to load more list items
|
||||
|
||||
## Intro
|
||||
|
||||
Loading more list items into the DOM from the backend is a common alternative to pagination. What's makes it different is that we need to append the new items to the existing list, rather than replace them.
|
||||
|
||||
## Goal
|
||||
|
||||
Our goal is to incrementally append list items into a specific part of the DOM, each time a button is clicked. Once five items are visible, the button should be removed.
|
||||
|
||||
## Demo
|
||||
|
||||
<div id="list" data-signals-offset="1">
|
||||
<div class="text-primary font-bold">Item 1</div>
|
||||
</div>
|
||||
<div>
|
||||
<button id="load-more" data-on-click="@get('/how_tos/load_more/data')" class="btn btn-primary font-bold">
|
||||
Click to load another item
|
||||
</button>
|
||||
</div>
|
||||
|
||||
## Steps
|
||||
|
||||
We'll give the list item container and the button unique IDs, so that we can target them individually.
|
||||
|
||||
We'll use a `data-signals-*` attribute to set the initial `offset` to `1`, and a `data-on-click` button that will send a `GET` request to the backend.
|
||||
|
||||
```html
|
||||
<div id="list">
|
||||
<div>Item 1</div>
|
||||
</div>
|
||||
<button id="load-more"
|
||||
data-signals-offset="1"
|
||||
data-on-click="@get('/how_tos/load_more/data')">
|
||||
Click to load another item
|
||||
</button>
|
||||
```
|
||||
|
||||
The backend will receive the `offset` signal and, if not above the max number of allowed items, will return the next item to be appended to the list.
|
||||
|
||||
We'll set up our backend to send a [`datastar-merge-fragments`](/reference/sse_events#datastar-merge-fragments) event with the `selector` option set to `#list` and the `mergeMode` option set to `append`. This tells Datastar to _append_ the fragments _into_ the `#list` container (rather than the default behaviour of replacing it).
|
||||
|
||||
```
|
||||
event: datastar-merge-fragments
|
||||
data: selector #list
|
||||
data: mergeMode append
|
||||
data: fragments <div>Item 2</div>
|
||||
```
|
||||
|
||||
In addition, we'll send a [`datastar-merge-signals`](/reference/sse_events#datastar-merge-signals) event to update the `offset`.
|
||||
|
||||
```
|
||||
event: datastar-merge-signals
|
||||
data: signals {offset: 2)
|
||||
```
|
||||
|
||||
In the case when the incoming offset is `2`, we'll remove the button from the DOM entirely.
|
||||
|
||||
```
|
||||
event: datastar-remove-fragments
|
||||
data: selector #load-more
|
||||
```
|
||||
|
||||
Here's how it might look using the SDKs.
|
||||
|
||||
!!!CODE_SNIPPET:how_tos/load_more!!!
|
||||
|
||||
## Conclusion
|
||||
|
||||
While using the default merge mode of `morph` is generally recommended, appending to a list is a good example of when to use an alternative merge mode.
|
|
@ -56,7 +56,7 @@ data: fragments </div>
|
|||
|
||||
Be careful not to add `.leading` to the modifier in the response, as it will cause the frontend to immediately send another request.
|
||||
|
||||
Here's how it would look using the SDKs.
|
||||
Here's how it might look using the SDKs.
|
||||
|
||||
!!!CODE_SNIPPET:how_tos/polling_1!!!
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ event: datastar-execute-script
|
|||
data: script window.location.href = "/guide"
|
||||
```
|
||||
|
||||
Here's how it would look using the SDKs.
|
||||
Here's how it might look using the SDKs.
|
||||
|
||||
!!!CODE_SNIPPET:how_tos/redirect_1!!!
|
||||
|
||||
|
|
Loading…
Reference in New Issue