mirror of
https://github.com/a-h/templ.git
synced 2025-02-06 10:03:16 +00:00
feat: templ.Join method renders multiple components into a single component (#929)
Co-authored-by: Adrian Hesketh <adrianhesketh@hushmail.com>
This commit is contained in:
parent
e59640f676
commit
3c65b4309b
@ -236,6 +236,43 @@ func main() {
|
||||
</div>
|
||||
```
|
||||
|
||||
## Joining Components
|
||||
|
||||
Components can be aggregated into a single Component using `templ.Join`.
|
||||
|
||||
```templ
|
||||
package main
|
||||
|
||||
templ hello() {
|
||||
<span>hello</span>
|
||||
}
|
||||
|
||||
templ world() {
|
||||
<span>world</span>
|
||||
}
|
||||
|
||||
templ helloWorld() {
|
||||
@templ.Join(hello(), world())
|
||||
}
|
||||
```
|
||||
|
||||
```go title="main.go"
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
helloWorld().Render(context.Background(), os.Stdout)
|
||||
}
|
||||
```
|
||||
|
||||
```html title="output"
|
||||
<span>hello</span><span>world</span>
|
||||
```
|
||||
|
||||
## Sharing and re-using components
|
||||
|
||||
Since templ components are compiled into Go functions by the `go generate` command, templ components follow the rules of Go, and are shared in exactly the same way as Go code.
|
||||
|
19
join.go
Normal file
19
join.go
Normal file
@ -0,0 +1,19 @@
|
||||
package templ
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Join returns a single `templ.Component` that will render provided components in order.
|
||||
// If any of the components return an error the Join component will immediately return with the error.
|
||||
func Join(components ...Component) Component {
|
||||
return ComponentFunc(func(ctx context.Context, w io.Writer) (err error) {
|
||||
for _, c := range components {
|
||||
if err = c.Render(ctx, w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
81
join_test.go
Normal file
81
join_test.go
Normal file
@ -0,0 +1,81 @@
|
||||
package templ_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/a-h/templ"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestJoin(t *testing.T) {
|
||||
compErr := errors.New("component error")
|
||||
|
||||
hello := templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
|
||||
if _, err := io.WriteString(w, "Hello"); err != nil {
|
||||
t.Fatalf("failed to write string: %v", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
world := templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
|
||||
if _, err := io.WriteString(w, "World"); err != nil {
|
||||
t.Fatalf("failed to write string: %v", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
err := templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
|
||||
return compErr
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input []templ.Component
|
||||
expectedOutput string
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
name: "a nil slice of components produces no output",
|
||||
input: nil,
|
||||
expectedOutput: "",
|
||||
},
|
||||
{
|
||||
name: "an empty list of components produces no output",
|
||||
input: []templ.Component{},
|
||||
expectedOutput: "",
|
||||
},
|
||||
{
|
||||
name: "components are rendered in order",
|
||||
input: []templ.Component{hello, world},
|
||||
expectedOutput: "HelloWorld",
|
||||
},
|
||||
{
|
||||
name: "components are rendered in order, and errors returned",
|
||||
input: []templ.Component{hello, err},
|
||||
expectedOutput: "Hello",
|
||||
expectedErr: compErr,
|
||||
},
|
||||
{
|
||||
name: "no further components are rendered after an error",
|
||||
input: []templ.Component{err, hello},
|
||||
expectedOutput: "",
|
||||
expectedErr: compErr,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := templ.Join(tt.input...)
|
||||
b := new(bytes.Buffer)
|
||||
err := got.Render(context.Background(), b)
|
||||
if err != tt.expectedErr {
|
||||
t.Fatalf("failed to render component: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(tt.expectedOutput, b.String()); diff != "" {
|
||||
t.Error(diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user