From 5eae1eef0f0a090ae569a23c0c52db356a109cfc Mon Sep 17 00:00:00 2001
From: Alan Pearce
Date: Wed, 19 Mar 2025 11:50:50 +0100
Subject: Add else part to If/Iff
---
gomponents.go | 25 ++++++++++++++--
gomponents_test.go | 88 ++++++++++++++++++++++++++++++++++++++----------------
2 files changed, 85 insertions(+), 28 deletions(-)
diff --git a/gomponents.go b/gomponents.go
index 37267d4..4867152 100644
--- a/gomponents.go
+++ b/gomponents.go
@@ -298,20 +298,39 @@ func (g Group) Render(w io.Writer) error {
// This helper function is good for inlining elements conditionally.
// If it's important that the given [Node] is only evaluated if condition is true
// (for example, when using nilable variables), use [Iff] instead.
-func If(condition bool, n Node) Node {
+func If(condition bool, n Node, otherwise ...Node) Node {
+ var o Node
+ switch len(otherwise) {
+ case 0:
+ case 1:
+ o = otherwise[0]
+ default:
+ panic("If must have just one or two nodes")
+ }
if condition {
return n
}
- return nil
+ return o
}
// Iff condition is true, call the given function. Otherwise, return nil.
// This helper function is good for inlining elements conditionally when the node depends on nilable data,
// or some other code that could potentially panic.
// If you just need simple conditional rendering, see [If].
-func Iff(condition bool, f func() Node) Node {
+func Iff(condition bool, f func() Node, otherwise ...func() Node) Node {
+ var o func() Node
+ switch len(otherwise) {
+ case 0:
+ case 1:
+ o = otherwise[0]
+ default:
+ panic("Iff must have just one or two nodes")
+ }
if condition {
return f()
}
+ if o != nil {
+ return o()
+ }
return nil
}
diff --git a/gomponents_test.go b/gomponents_test.go
index eb5bed3..f3cb1b8 100644
--- a/gomponents_test.go
+++ b/gomponents_test.go
@@ -103,16 +103,19 @@ func TestEl(t *testing.T) {
assert.Equal(t, "
", e)
})
- t.Run("renders an empty element without closing tag if it's a void kind element", func(t *testing.T) {
- e := g.El("hr")
- assert.Equal(t, "", e)
-
- e = g.El("br")
- assert.Equal(t, " ", e)
-
- e = g.El("img")
- assert.Equal(t, "", e)
- })
+ t.Run(
+ "renders an empty element without closing tag if it's a void kind element",
+ func(t *testing.T) {
+ e := g.El("hr")
+ assert.Equal(t, "", e)
+
+ e = g.El("br")
+ assert.Equal(t, " ", e)
+
+ e = g.El("img")
+ assert.Equal(t, "", e)
+ },
+ )
t.Run("renders an empty element if only attributes given as children", func(t *testing.T) {
e := g.El("div", g.Attr("class", "hat"))
@@ -124,10 +127,13 @@ func TestEl(t *testing.T) {
assert.Equal(t, `
`, e)
})
- t.Run("renders attributes at the correct place regardless of placement in parameter list", func(t *testing.T) {
- e := g.El("div", g.El("br"), g.Attr("class", "hat"))
- assert.Equal(t, `
`, e)
- })
+ t.Run(
+ "renders attributes at the correct place regardless of placement in parameter list",
+ func(t *testing.T) {
+ e := g.El("div", g.El("br"), g.Attr("class", "hat"))
+ assert.Equal(t, `
`, e)
+ },
+ )
t.Run("renders outside if node does not implement nodeTypeDescriber", func(t *testing.T) {
e := g.El("div", outsider{})
@@ -201,8 +207,11 @@ func TestRaw(t *testing.T) {
}
func ExampleRaw() {
- e := g.El("span",
- g.Raw(` > normal hats.`),
+ e := g.El(
+ "span",
+ g.Raw(
+ ` > normal hats.`,
+ ),
)
_ = e.Render(os.Stdout)
// Output: > normal hats.
@@ -216,8 +225,12 @@ func TestRawf(t *testing.T) {
}
func ExampleRawf() {
- e := g.El("span",
- g.Rawf(` > normal hats.`, "Party time!"),
+ e := g.El(
+ "span",
+ g.Rawf(
+ ` > normal hats.`,
+ "Party time!",
+ ),
)
_ = e.Render(os.Stdout)
// Output: > normal hats.
@@ -277,7 +290,10 @@ func TestGroup(t *testing.T) {
})
t.Run("does not ignore attributes at the second level and below", func(t *testing.T) {
- children := []g.Node{g.El("div", g.Attr("class", "hat"), g.El("hr", g.Attr("id", "partyhat"))), g.El("span")}
+ children := []g.Node{
+ g.El("div", g.Attr("class", "hat"), g.El("hr", g.Attr("id", "partyhat"))),
+ g.El("span"),
+ }
e := g.Group(children)
assert.Equal(t, `
`, e)
})
@@ -321,14 +337,21 @@ func TestIf(t *testing.T) {
n := g.El("div", g.If(false, g.El("span")))
assert.Equal(t, "", n)
})
+
+ t.Run("returns second node if given and condition is false", func(t *testing.T) {
+ n := g.El("div", g.If(false, g.Text("first"), g.Text("second")))
+ assert.Equal(t, "
second
", n)
+ })
}
func ExampleIf() {
showMessage := true
e := g.El("div",
- g.If(showMessage, g.El("span", g.Text("You lost your hat!"))),
- g.If(!showMessage, g.El("span", g.Text("No messages."))),
+ g.If(showMessage,
+ g.El("span", g.Text("You lost your hat!")),
+ g.El("span", g.Text("No messages.")),
+ ),
)
_ = e.Render(os.Stdout)
@@ -349,6 +372,15 @@ func TestIff(t *testing.T) {
}))
assert.Equal(t, "", n)
})
+
+ t.Run("returns second node if given and condition is false", func(t *testing.T) {
+ n := g.El("div", g.Iff(false, func() g.Node {
+ return g.Text("first")
+ }, func() g.Node {
+ return g.Text("second")
+ }))
+ assert.Equal(t, "