# Templates: Using Actions, Functions, and Custom Functions

[My previous blog post](https://alissalozhkin.hashnode.dev/how-to-create-plaintext-reports-in-go-using-templates-with-loops-and-conditionals) introduced the feature of actions in templates. Another very similar feature is a function, which can be used together with an action to perform additional operations on the data. For example, `{{ range }}` is an action as it contributes to the overall structure of the template, whereas `{{ len }}` is a function as it performs a calculation. In this blog post, I will first demo how to use actions and functions together. I will then go over how to use custom functions in templates. We start with the following code in `main.go`:

```go
package main

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

type Person struct {
    Name       string
    Age        int
    Employed   bool
    Occupation string
    Interests  []string
}

func main() {
    people := []Person{
        {
            Name:       "Bob",
            Age:        42,
            Employed:   true,
            Occupation: "Doctor",
            Interests:  []string{"Reading", "Swimming"},
        },
        {
            Name:       "Jessica",
            Age:        22,
            Employed:   true,
            Occupation: "Teacher",
            Interests:  []string{"Piano", "Baking"},
        },
        {
            Name:       "Ben",
            Age:        23,
            Employed:   true,
            Occupation: "Photographer",
            Interests:  []string{"Music", "Running"},
        },
    }
    tmplFile := "demo.tmpl"
    tmpl, err := template.New(tmplFile).ParseFiles(tmplFile)
    if err != nil {
        panic(err)
    }
    err = tmpl.Execute(os.Stdout, people)
    if err != nil {
        panic(err)
    }
}
```

Note that I added an attribute called `Interests` (slice of `strings`) to the `Person` struct. For an explanation of this code, please read [my previous post](https://alissalozhkin.hashnode.dev/how-to-create-plaintext-reports-in-go-using-templates-with-loops-and-conditionals).

In `demo.tmpl`, we can use the `slice` function and the `range` action to loop over a section of the slice `people`.

```go
{{ range slice . 1 2 }}
-----------------
Name: {{.Name}}
Age: {{.Age}}
Occupation: {{ if .Employed }}{{ .Occupation }}{{ else }}Unemployed{{end}}
{{ end }}
```

`{{ slice . 1 2 }}` is equivalent to `people[1:2]`, and so calling `range` on this slice iterates through the second element of `people` and prints out the following string:

```go
-----------------
Name: Jessica
Age: 22
Occupation: Teacher
```

For the purpose of printing out one element, it may be easier to use the `index` function. For example, the line `{{ index . 0 }}` is equivalent to `people[0]` and would print out `{Bob 42 true Doctor [Reading Swimming]}`.

Creating a plaintext report solely through the use of actions and built-in functions in templates can be quite restrictive as arithmetic operations cannot be used in templates directly.

Introducing the option to feed in custom functions to your templates. These functions can be defined however you want, and they give you the possibility to perform operations that are otherwise not allowed in templates.

Let’s say you want to index the last element of the slice you pass in. If you know the length of the slice, then you can simply hardcode the index number. But to make this more reusable, we need to pass in a custom function that allows us to decrement the length by one so that we can index the last element of any slice.

We start by defining a new function called `sub` in `main.go`:

```go
func sub(i int) int {
    return i - 1
}
```

In the `main` function, we create a map `fMap` that maps a function name (`string`) to the function definition. We then pass this into the template through the `template.New().Funcs` function:

```go
fMap := template.FuncMap{
	"sub": sub,
}
tmpl, err := template.New(tmplFile).Funcs(fMap).ParseFiles(tmplFile)
if err != nil {
	panic(err)
}
err = tmpl.Execute(os.Stdout, people)
if err != nil {
	panic(err)
}
```

In the template file, we write `{{ len . | sub | index . }}` , indicating that the length of the slice is passed to the `sub` function, and the output of the `sub` function is passed to the `index` function. Therefore, when passing in the slice `people`, the output of this line is `people[2]` or `{ Ben 23 true Photographer [Music Running]}`.

In a similar way, we can pass built-in Go functions into a template. For example, let’s say we want to convert the slice of `Interests` into a string where each interest is separated by `&` . To do this, we first pass in the function `strings.Join` to the template by adding a key-value pair to `fMap` like so:

```go
fMap := template.FuncMap{
	"sub":  sub,
    "join": strings.Join,
}
```

Going back to `demo.tmpl`, this time looping through the whole slice, we can use this function to return the desired string:

```go
{{ range . }}
-----------------
Name: {{.Name}}
Age: {{.Age}}
Occupation: {{ if .Employed }}{{ .Occupation }}{{ else }}Unemployed{{end}}
Interests: {{ join .Interests " & " }}
{{ end }}
```

Saving `demo.tmpl` and running `go run main.go` gives the following result:

```go
-----------------
Name: Bob
Age: 42
Occupation: Doctor
Interests: Reading & Swimming

-----------------
Name: Jessica
Age: 22
Occupation: Teacher
Interests: Piano & Baking

-----------------
Name: Ben
Age: 23
Occupation: Photographer
Interests: Music & Running
```
