Skip to content

Commit

Permalink
Add an Iff helper (#172)
Browse files Browse the repository at this point in the history
I ran into some situation where I want to conditionally render a node if
some variable is not nil and obviously I got a panic

```go
// package viewmodels
type SomePage struct {
	s *string
}

// package views
func SomePage (vm viewmodels.SomePage) g,Node {
	return Div(
		If(vm.s == nil, Text("s is nil"),
		If(vm.s !- nil, Text("s is " + vm.s), // this will panic when `s` is nil
	)
}
```

In this situation, go will interpret the code of the second `if`
regardless of the condition because the code itself is not in a
condition.

This PR introduces a new `Iff` helper that accepts a callback. The
callback content is only interpreted when it's called, making the code
safe:

```go
// package viewmodels
type SomePage struct {
	s *string
}

// package views
func SomePage (vm viewmodels.SomePage) g,Node {
	return Div(
		Iff(vm.s == nil, func () g.Node { return Text("s is nil") },
		Iff(vm.s !- nil, func () g.Node { return Text("s is " + vm.s) },
	)
}
```

I'm aware of the `Lazy` effort on the side, but I guess this is no a
breaking change and can still exist in addition to the `Lazy` effort.

Co-authored-by: Markus Wüstenberg <markus@maragu.dk>
  • Loading branch information
JulienTant and markuswustenberg committed Jun 19, 2024
1 parent a75b253 commit dafb3da
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 0 deletions.
11 changes: 11 additions & 0 deletions gomponents.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,20 @@ func Group(children []Node) Node {

// If condition is true, return the given Node. Otherwise, return nil.
// This helper function is good for inlining elements conditionally.
// If your condition and node involve a nilable variable, use iff because
// go will evaluate the node regardless of the condition.
func If(condition bool, n Node) Node {
if condition {
return n
}
return nil
}

// Iff execute the function f if condition is true, otherwise return nil.
// it is the preferred way to conditionally render a node if the node involves a nilable variable.
func Iff(condition bool, f func() Node) Node {
if condition {
return f()
}
return nil
}
29 changes: 29 additions & 0 deletions gomponents_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,32 @@ func ExampleIf() {
_ = e.Render(os.Stdout)
// Output: <div><span>You lost your hat!</span></div>
}

func TestIff(t *testing.T) {
t.Run("returns node if condition is true", func(t *testing.T) {
n := g.El("div", g.Iff(true, func() g.Node {
return g.El("span")
}))
assert.Equal(t, "<div><span></span></div>", n)
})

t.Run("returns nil if condition is false", func(t *testing.T) {
n := g.El("div", g.Iff(false, func() g.Node {
return g.El("span")
}))
assert.Equal(t, "<div></div>", n)
})
}

func ExampleIff() {
var nillableVariable *struct {
str string
}
e := g.El("div",
g.Iff(nillableVariable != nil, func() g.Node {
return g.Text(nillableVariable.str)
}),
)
_ = e.Render(os.Stdout)
// Output: <div></div>
}

0 comments on commit dafb3da

Please sign in to comment.