Common dynamic data
In some web applications there may be common dynamic data that you want to include on more than one — or even every — webpage. For example, you might want to include the name and profile picture of the current user, or a CSRF token in all pages with forms.
In our case let’s begin with something simple, and say that we want to include the current year in the footer on every page.
To do this we’ll begin by adding a new CurrentYear
field to the templateData
struct, like so:
package main ... // Add a CurrentYear field to the templateData struct. type templateData struct { CurrentYear int Snippet models.Snippet Snippets []models.Snippet } ...
The next step is to add a newTemplateData()
helper method to our application, which will return a templateData
struct initialized with the current year.
I’ll demonstrate:
package main import ( "bytes" "fmt" "net/http" "time" // New import ) ... // Create an newTemplateData() helper, which returns a pointer to a templateData // struct initialized with the current year. Note that we're not using the // *http.Request parameter here at the moment, but we will do later in the book. func (app *application) newTemplateData(r *http.Request) templateData { return templateData{ CurrentYear: time.Now().Year(), } } ...
Then let’s update our home
and snippetView
handlers to use the newTemplateData()
helper, like so:
package main ... func (app *application) home(w http.ResponseWriter, r *http.Request) { w.Header().Add("Server", "Go") snippets, err := app.snippets.Latest() if err != nil { app.serverError(w, r, err) return } // Call the newTemplateData() helper to get a templateData struct containing // the 'default' data (which for now is just the current year), and add the // snippets slice to it. data := app.newTemplateData(r) data.Snippets = snippets // Pass the data to the render() helper as normal. app.render(w, r, http.StatusOK, "home.tmpl", data) } func (app *application) snippetView(w http.ResponseWriter, r *http.Request) { id, err := strconv.Atoi(r.PathValue("id")) if err != nil || id < 1 { http.NotFound(w, r) return } snippet, err := app.snippets.Get(id) if err != nil { if errors.Is(err, models.ErrNoRecord) { http.NotFound(w, r) } else { app.serverError(w, r, err) } return } // And do the same thing again here... data := app.newTemplateData(r) data.Snippet = snippet app.render(w, r, http.StatusOK, "view.tmpl", data) } ...
And then the final thing we need to do is update the ui/html/base.tmpl
file to display the year in the footer, like so:
{{define "base"}} <!doctype html> <html lang='en'> <head> <meta charset='utf-8'> <title>{{template "title" .}} - Snippetbox</title> <link rel='stylesheet' href='/static/css/main.css'> <link rel='shortcut icon' href='/static/img/favicon.ico' type='image/x-icon'> <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700'> </head> <body> <header> <h1><a href='/'>Snippetbox</a></h1> </header> {{template "nav" .}} <main> {{template "main" .}} </main> <footer> <!-- Update the footer to include the current year --> Powered by <a href='https://golang.org/'>Go</a> in {{.CurrentYear}} </footer> <script src='/static/js/main.js' type='text/javascript'></script> </body> </html> {{end}}
If you restart the application and visit the home page at http://localhost:4000
, you now should see the current year in the footer. Like this:
