programming

10 How to Understanding HTML Template Data in Golang

Introduction to Data Templates

If you have studied HTML Templates in the previous article, then we will continue with data templates where we can display this data dynamically by using struct or map data. However, we need to know the changes in the template text. We need to know the name of the field or key that we will use to fill in the dynamic data in the template. We can mention the name of the field or key, for example {{.FieldName}}.

Apply to Project Handler

We first create a template in the templates folder by creating a new file name.html with contents as follows.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>{{ .Title }}</title>
  </head>
  <body>
    <h1>Hello {{ .Name }}</h1>
  </body>
</html>

If we look at the HTML code above, it is very simple, we will send the Title and Name data from the handler to the HTML template. Next, we create a handler function as below.

func TemplateDataStructHandler(w http.ResponseWriter, r *http.Request) {
	t := template.Must(template.ParseFiles("./templates/name.html"))
	t.ExecuteTemplate(w, "name.html", map[string]interface{}{
		"Title": "Template Data Struct",
		"Name":  "Santekno",
	})
}

If you want to use struct, the difference is actually the same, namely that we send the template a struct which we have defined as in the example below.

type Page struct {
	Title string
	Name  string
}

func TemplateDataStructHandler(w http.ResponseWriter, r *http.Request) {
	t := template.Must(template.ParseFiles("./templates/name.html"))
	t.ExecuteTemplate(w, "name.html", Page{
		Title: "Template Data Struct",
		Name:  "Santekno",
	})
}

And don’t forget to also add the handler function to initiate mux with a different endpoint like this.

mux.HandleFunc("/template-data-map", TemplateDataMapHandler)
mux.HandleFunc("/template-data-struct", TemplateDataStructHandler)

So we can run our program then open the browser and access this endpoint, then a page will appear with the title Data Struct Template and an HTML tag called Santekno.

http://localhost:8080/template-data-struct
http://localhost:8080/template-data-map

HTML Template Testing

The way we test the handler function that we have created is by using a unit test as below.

func TestTemplateDataMapHandler(t *testing.T) {
	tests := []struct {
		name string
		want string
	}{
		{
			name: "get from embed",
			want: "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\">\n    <title>Template Data Map</title>\n  </head>\n  <body>\n    <h1>Hello Santekno</h1>\n  </body>\n</html>",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			request := httptest.NewRequest(http.MethodGet, "http://localhost/file", nil)
			recorder := httptest.NewRecorder()
			TemplateDataMapHandler(recorder, request)

			body, _ := io.ReadAll(recorder.Result().Body)
			bodyString := string(body)

			if !reflect.DeepEqual(bodyString, tt.want) {
				t.Errorf("response = %#v, want = %#v\n", bodyString, tt.want)
			}
		})
	}
}

func TestTemplateDataStructHandler(t *testing.T) {
	tests := []struct {
		name string
		want string
	}{
		{
			name: "get from embed",
			want: "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\">\n    <title>Template Data Struct</title>\n  </head>\n  <body>\n    <h1>Hello Santekno</h1>\n  </body>\n</html>",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			request := httptest.NewRequest(http.MethodGet, "http://localhost/file", nil)
			recorder := httptest.NewRecorder()
			TemplateDataStructHandler(recorder, request)

			body, _ := io.ReadAll(recorder.Result().Body)
			bodyString := string(body)

			if !reflect.DeepEqual(bodyString, tt.want) {
				t.Errorf("response = %#v, want = %#v\n", bodyString, tt.want)
			}
		})
	}
}

In this unit test we ensure that the input sent from the handler matches the HTML template response sent.

comments powered by Disqus