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
	)
}