6

I want to create a golang template with a default value that is used if a parameter is not supplied, but if I try to use the or function in my template, it gives me this error:

template: t2:2:20: executing "t2" at <index .table_name 0>: error calling index: index of untyped nil

Here's an example of the code: https://play.golang.org/p/BwlpROrhm6

// text/template is a useful text generating tool.
// Related examples: http://golang.org/pkg/text/template/#pkg-examples
package main

import (
    "fmt"
    "os"
    "text/template"
)

var fullParams = map[string][]string{
    "table_name": []string{"TableNameFromParameters"},
    "min":        []string{"100"},
    "max":        []string{"500"},
}
var minimalParams = map[string][]string{
    "min": []string{"100"},
    "max": []string{"500"},
}

func check(err error) {
    if err != nil {
        fmt.Print(err)
    }
}

func main() {
    // Define Template
    t := template.Must(template.New("t2").Parse(`
        {{$table_name := (index .table_name 0) or "DefaultTableName"}}
        Hello World!
        The table name is {{$table_name}}
    `))
    check(t.Execute(os.Stdout, fullParams))
    check(t.Execute(os.Stdout, minimalParams))
}

Googling has pointed me towards an isset function in hugo's template engine, but I can't figure out how they implemented it, and I am not sure if it would even solve my problem.

Noah
  • 495
  • 2
  • 7
  • 21

3 Answers3

14

You can use the function or in the template. This seems the simplest option.

{or .value "Default"}

From the docs:

or
        Returns the boolean OR of its arguments by returning the
        first non-empty argument or the last argument, that is,
        "or x y" behaves as "if x then x else y". All the
        arguments are evaluated.

https://golang.org/pkg/text/template/#hdr-Functions

Playground Demo

robstarbuck
  • 6,893
  • 2
  • 41
  • 40
  • Granted that `.value` is always present, right? – x-yuri Jul 13 '21 at 00:02
  • 1
    To make it work with missing keys (at least under `docker`): `{{or (index . "Key") "Default"}}`. – x-yuri Jul 13 '21 at 00:29
  • I've included a demo, I hope that's some help. The docker environment should make no difference to how templates function. – robstarbuck Jul 13 '21 at 09:43
  • What about [this one](https://play.golang.org/p/CWYTIWW4vi_3). And 'map has no entry for key "Slot"' is exactly what gives me Docker. – x-yuri Jul 16 '21 at 18:53
  • 1
    Right, I think see what you mean, yes if you're accessing a key in a map rather than a key in a struct you will need the syntax that you mentioned: https://play.golang.org/p/loWbi4mbpL4 More mentioned here: https://stackoverflow.com/questions/26152088/access-a-map-value-using-a-variable-key-in-a-go-template This shouldn't have anything to do with Docker though. – robstarbuck Jul 16 '21 at 21:40
7

Another solution is by changing the template definition to

// Define Template
t := template.Must(template.New("t2").Parse(`
    Hello World!
    The table name is {{with .table_name}}{{index . 0}}{{else}}DefaultTableName{{end}}
`))

But, the value won't be stored in a variable, so if you want to reuse it in other places, you need to write it again. The main purpose of the standard template package is for rendering precomputed value, and logic related operations/functions have limited capability. However, you can define your own function then register it to the template's FuncMap e.g. the default function mentioned by @jeevatkm.

putu
  • 6,218
  • 1
  • 21
  • 30
  • 1
    It's certainly not pretty, but it works! I think you're right about the intended purpose--I should probably be handing defaults outside of the template. I will keep that in mind for a future revision of this project. – Noah Jun 14 '17 at 19:08
2

Go template does not have default function. However you can use library that provides default func.

For e.g.: github.com/leekchan/gtf

Refer here, how it is implemented at https://github.com/leekchan/gtf/blob/master/gtf.go#L28


Read hugo isset func here and source is here

jeevatkm
  • 4,571
  • 1
  • 23
  • 24