lazy.mdin: /docs/internal/components/
components.Lazy - url=/not_found delay= placeholder=<nil>
...loading...
components.Lazy - url=/e/text delay= placeholder=<nil>
...loading...
components.Lazy - url=/e/text delay=5s placeholder=custom placeholder... with delay
custom placeholder... with delay
components.Lazy !!FAILED!! - url= delay= placeholder=<nil>
Error Captured by component:
tpl 'component': slot 'body': View(components.Lazy): no url
When building websites, sometimes it's really nice to have the chunk of the page load lazilly and separately from everything else.
import (
"context"
"errors"
"fmt"
"github.com/stanistan/veun"
"github.com/stanistan/veun/el"
)
Lazy Loading
We have htmx loaded client side, so we can leverage that and plain old http/html responses to accomplish this.
Our struct takes a URL to load content from, a placeholder view, and a delay.
type Lazy struct {
URL string
Placeholder veun.AsView
Delay string
}
How does this render?
func (v Lazy) View(ctx context.Context) (*veun.View, error) {
if v.URL == "" {
return nil, errors.New("no url")
}
return el.Div{
v.htmxAttrs(),
el.Content{v.placeholder()},
}.View(ctx)
}
We get our attributes for htmx
:
func (v Lazy) htmxAttrs() el.Attrs {
trigger := "load"
if v.Delay != "" {
trigger += " delay:" + v.Delay
}
return el.Attrs{"hx-get": v.URL, "hx-trigger": trigger}
}
And a default placeholder:
func (v Lazy) placeholder() veun.AsView {
if v.Placeholder == nil {
return el.Em{el.Text("...loading...")}
} else {
return v.Placeholder
}
}
A component
Lazy
is a component...
var _ IComponent = Lazy{}
func (v Lazy) Description() string {
return fmt.Sprintf("url=%s delay=%s placeholder=%+v", v.URL, v.Delay, v.Placeholder)
}
what our components show it
func init() {
show(
Lazy{URL: "/not_found"},
Lazy{URL: "/e/text"},
Lazy{URL: "/e/text", Placeholder: el.Text("custom placeholder... with delay"), Delay: "5s"},
Lazy{}, // Missing URL
)
}