Chapter 16 - HTML Templates

Exercise 1: A Text Template

We want to create a text template that will output a bulleted list (using simple dash characters as the bullets). Set the templateText variable so that the program will produce the output shown. Don’t forget that you need a newline character to make the output skip to the next line!

package main

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

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func executeTemplate(templateText string, data interface{}) {
	tmpl, err := template.New("template").Parse(templateText)
	check(err)
	err = tmpl.Execute(os.Stdout, data)
	check(err)
}

func main() {
	// YOUR CODE HERE:
	// Set templateText so that the calls to executeTemplate
	// below will produce the output shown.
	templateText := ""
	executeTemplate(templateText,
		[]string{"apples", "oranges", "pears"})
	executeTemplate(templateText,
		[]string{"chicken", "beef", "lamb"})
}

Output:

- apples
- oranges
- pears
- chicken
- beef
- lamb

When you’re ready, have a look at our solution.

Exercise 2: An HTML Template

Copy the code below to grocery.go and list.html files, both saved in the same directory. Then fill in the missing code in both files.

When a browser visits http://localhost:8080/fruit, your app should respond with this HTML (the spacing doesn’t have to match):

<html>
  <ul>
    <li>apples</li>
    <li>oranges</li>
    <li>pears</li>
  </ul>
</html>

And when a browser visits http://localhost:8080/meat, your app should respond with this HTML:

<html>
  <ul>
    <li>chicken</li>
    <li>beef</li>
    <li>lamb</li>
  </ul>
</html>

Try running your finished app, and visit the above URLs in your browser!

grocery.go

package main

import (
	"html/template"
	"log"
	"net/http"
)

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func writeList(writer http.ResponseWriter, list []string) {
	// YOUR CODE HERE: Use the template library to parse the contents
	// of the "list.html" file. You'll get a template value and an
	// error value.
	// Pass the error value to the "check" function.
	// Now call the "Execute" method on the template. It should write
	// its output to the "writer" parameter, and it should use the
	// "list" parameter as its data value.
	// You'll get another error value back from "Execute", which
	// should be passed to "check".
}

func fruitHandler(writer http.ResponseWriter, request *http.Request) {
	writeList(writer, []string{"apples", "oranges", "pears"})
}

func meatHandler(writer http.ResponseWriter, request *http.Request) {
	writeList(writer, []string{"chicken", "beef", "lamb"})
}

func main() {
	http.HandleFunc("/fruit", fruitHandler)
	http.HandleFunc("/meat", meatHandler)
	err := http.ListenAndServe("localhost:8080", nil)
	log.Fatal(err)
}

list.html

<html>
  <ul>
    <!-- YOUR CODE HERE:
         The data value passed to the template should be a slice.
         Loop over each element in the slice, and include them in
         the output, enclosed in <li></li> tags. -->
  </ul>
</html>

Here’s our solution.