Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: add neater support for code components into templ.Once #755

Merged
merged 1 commit into from
May 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.2.702
0.2.705
25 changes: 23 additions & 2 deletions once.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,27 @@ import (
// onceHandleIndex is used to identify unique once handles in a program run.
var onceHandleIndex int64

type OnceOpt func(*OnceHandle)

// WithOnceComponent sets the component to be rendered once per context.
// This can be used instead of setting the children of the `Once` method,
// for example, if creating a code component outside of a templ HTML template.
func WithComponent(c Component) OnceOpt {
return func(o *OnceHandle) {
o.c = c
}
}

// NewOnceHandle creates a OnceHandle used to ensure that the children of its
// `Once` method are only rendered once per context.
func NewOnceHandle() *OnceHandle {
return &OnceHandle{
func NewOnceHandle(opts ...OnceOpt) *OnceHandle {
oh := &OnceHandle{
id: atomic.AddInt64(&onceHandleIndex, 1),
}
for _, opt := range opts {
opt(oh)
}
return oh
}

// OnceHandle is used to ensure that the children of its `Once` method are are only
Expand All @@ -28,6 +43,9 @@ type OnceHandle struct {
//
// https://go.dev/ref/spec#Size_and_alignment_guarantees
id int64
// c is the component to be rendered once per context.
// if c is nil, the children of the `Once` method are rendered.
c Component
}

// Once returns a component that renders its children once per context.
Expand All @@ -38,6 +56,9 @@ func (o *OnceHandle) Once() Component {
return nil
}
v.setHasBeenRendered(o)
if o.c != nil {
return o.c.Render(ctx, w)
}
return GetChildren(ctx).Render(ctx, w)
})
}
11 changes: 11 additions & 0 deletions once_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,15 @@ func TestOnceHandle(t *testing.T) {
t.Errorf("unexpected diff:\n%v", diff)
}
})
t.Run("a handle can be used to render a specific component", func(t *testing.T) {
ctx := templ.WithChildren(context.Background(), templ.Raw("child"))
o := templ.NewOnceHandle(templ.WithComponent(templ.Raw("c"))).Once()
var w strings.Builder
if err := o.Render(ctx, &w); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if diff := cmp.Diff("c", w.String()); diff != "" {
t.Errorf("unexpected diff:\n%v", diff)
}
})
}
Loading