• No results found

Rendering the Edit Page

In document Web Development with Go.pdf (Page 108-114)

The Edit page is used to edit an existing Note object. edit.html is used to provide the contents for the head and body sections (see Listing 5-19).

Listing 5-19. Template Definitions in edit.html

{{define "head"}}<title>Edit Note</title>{{end}} {{define "body"}}

<h1>Edit Note</h1>

<form action="/notes/update/{{.Id}}" method="post">

<p>Title:<br> <input type="text" value="{{.Note.Title}}" name="title"></p> <p> Description:<br> <textarea rows="4" cols="50" name="description">

{{.Note.Description}}</textarea> </p> <p><input type="submit" value="submit"/></p> </form>

{{end}}

In edit.html, the data elements of the Note object are mapped with HTML form field values to edit an existing item. This template definition maps with the data object of the EditNote struct that contains an id for the item to be edited, along with the Note object for editing the fields of the Note object. When the template for rendering the Edit page is executed, an instance of the EditNote struct is provided as the data object (see Listing 5-20).

Listing 5-20. Data Model for Editing an Item //View Model for edit

type EditNote struct { Note

Id string }

When the HTTP server gets the request for the "/notes/edit/{id}" route, it calls the editNote handler function (see Listing 5-21).

Listing 5-21. Handler Function for “/notes/edit/{id}” in main.go //Handler for "/notes/edit/{id}" to edit an existing item func editNote(w http.ResponseWriter, r *http.Request) { var viewModel EditNote

//Read value from route variable vars := mux.Vars(r)

Chapter 5 ■ Working With go templates

if note, ok := noteStore[k]; ok { viewModel = EditNote{note, k} }else {

http.Error(w, "Could not find the resource to edit.", http.StatusBadRequest) }

renderTemplate(w, "edit", "base", viewModel) }

An EditNote struct instance is provided as the data object to the template definition. The string "edit" is provided as the key of the map object for getting the parsed template, which was parsed by using template definition files edit.html and base.html, for rendering the Edit page.

Figure 5-4 shows the Edit page that provides the user interface to edit an existing Note.

When the user submits the HTML form after editing the values of the Note object, an HTTP POST request is sent to the server for a URL "/notes/update/{id}" that will be handled by the handler function shown in Listing 5-22.

Listing 5-22. Handler for “/notes/update/{id}” to Update an Existing Item in main.go //Handler for "/notes/update/{id}" which update an item into the data store func updateNote(w http.ResponseWriter, r *http.Request) {

//Read value from route variable vars := mux.Vars(r)

k := vars["id"] var noteToUpd Note

if note, ok := noteStore[k]; ok { r.ParseForm()

noteToUpd.Title = r.PostFormValue("title")

noteToUpd.Description = r.PostFormValue("description") noteToUpd.CreatedOn = note.CreatedOn

Chapter 5 ■ Working With go templates

//delete existing item and add the updated item delete(noteStore, k)

noteStore[k] = noteToUpd } else {

http.Error(w, "Could not find the resource to update.", http.StatusBadRequest) }

http.Redirect(w, r, "/", 302) }

Similar to adding a new Note object in Listing 5-18, the form field values from the *http.Request object are parsed, and the values of the Note object are updated. The request is then redirected to "/" for redirecting to the Index page, in which the updated values can be seen.

The full source of main.go is provided in Listing 5-23. Listing 5-23. main.go package main import ( "html/template" "log" "net/http" "strconv" "time" "github.com/gorilla/mux" )

type Note struct { Title string Description string CreatedOn time.Time }

//View Model for edit type EditNote struct { Note

Id string }

//Store for the Notes collection var noteStore = make(map[string]Note)

//Variable to generate key for the collection var id int = 0

Chapter 5 ■ Working With go templates

//Compile view templates func init() { if templates == nil { templates = make(map[string]*template.Template) } templates["index"] = template.Must(template.ParseFiles("templates/index.html", "templates/base.html")) templates["add"] = template.Must(template.ParseFiles("templates/add.html", "templates/base.html")) templates["edit"] = template.Must(template.ParseFiles("templates/edit.html", "templates/base.html")) }

//Render templates for the given name, template definition and data object

func renderTemplate(w http.ResponseWriter, name string, template string, viewModel interface{}) {

// Ensure the template exists in the map. tmpl, ok := templates[name]

if !ok {

http.Error(w, "The template does not exist.", http.StatusInternalServerError) }

err := tmpl.ExecuteTemplate(w, template, viewModel) if err != nil {

http.Error(w, err.Error(), http.StatusInternalServerError) }

}

//Handler for "/notes/save" for save a new item into the data store func saveNote(w http.ResponseWriter, r *http.Request) {

r.ParseForm()

title := r.PostFormValue("title") desc := r.PostFormValue("description") note := Note{title, desc, time.Now()}

//increment the value of id for generating key for the map id++

//convert id value to string k := strconv.Itoa(id) noteStore[k] = note

http.Redirect(w, r, "/", 302) }

//Handler for "/notes/add" for add a new item

func addNote(w http.ResponseWriter, r *http.Request) { renderTemplate(w, "add", "base", nil)

Chapter 5 ■ Working With go templates

//Handler for "/notes/edit/{id}" to edit an existing item func editNote(w http.ResponseWriter, r *http.Request) { var viewModel EditNote

//Read value from route variable vars := mux.Vars(r)

k := vars["id"]

if note, ok := noteStore[k]; ok { viewModel = EditNote{note, k} } else {

http.Error(w, "Could not find the resource to edit.", http.StatusBadRequest) }

renderTemplate(w, "edit", "base", viewModel) }

//Handler for "/notes/update/{id}" which update an item into the data store func updateNote(w http.ResponseWriter, r *http.Request) {

//Read value from route variable vars := mux.Vars(r)

k := vars["id"] var noteToUpd Note

if note, ok := noteStore[k]; ok { r.ParseForm()

noteToUpd.Title = r.PostFormValue("title")

noteToUpd.Description = r.PostFormValue("description") noteToUpd.CreatedOn = note.CreatedOn

//delete existing item and add the updated item delete(noteStore, k)

noteStore[k] = noteToUpd } else {

http.Error(w, "Could not find the resource to update.", http.StatusBadRequest) }

http.Redirect(w, r, "/", 302) }

//Handler for "/notes/delete/{id}" which delete an item form the store func deleteNote(w http.ResponseWriter, r *http.Request) {

//Read value from route variable vars := mux.Vars(r)

k := vars["id"] // Remove from Store

if _, ok := noteStore[k]; ok { //delete existing item delete(noteStore, k) } else {

http.Error(w, "Could not find the resource to delete.", http.StatusBadRequest) }

http.Redirect(w, r, "/", 302) }

Chapter 5 ■ Working With go templates

//Handler for "/" which render the index page

func getNotes(w http.ResponseWriter, r *http.Request) { renderTemplate(w, "index", "base", noteStore) }

//Entry point of the program func main() { r := mux.NewRouter().StrictSlash(false) fs := http.FileServer(http.Dir("public")) r.Handle("/public/", fs) r.HandleFunc("/", getNotes) r.HandleFunc("/notes/add", addNote) r.HandleFunc("/notes/save", saveNote) r.HandleFunc("/notes/edit/{id}", editNote) r.HandleFunc("/notes/update/{id}", updateNote) r.HandleFunc("/notes/delete/{id}", deleteNote) server := &http.Server{ Addr: ":8080", Handler: r, } log.Println("Listening...") server.ListenAndServe() }

In this example, a full web application was completed in Go by leveraging the standard library package html/template for rendering the user interfaces with dynamic data. Template definition files are parsed and put into a map object so that you can easily get the parsed template files whenever you want to execute the templates. This approach allows you to avoid parsing the template files every time the templates are executed, which improves web application performance. By leveraging the various techniques shown in this example application, you can build real-world web applications.

Summary

This chapter showed how to work with Go templates by developing a web application. When you work with data-driven web applications, you have to leverage templates to render HTML pages in which you can combine static contents with dynamic contents by applying a data object to the templates.

The html/template package is used to render HTML pages. It also provides a security mechanism against various code injections while rendering the HTML output. Both html/template and text/template provide the same interface for the template authors, in which html/template generates HTML output, and text/template generates textual output. By leveraging the standard library packages net/http and html/template, you can build full-fledged web applications in Go.

Chapter 6

In document Web Development with Go.pdf (Page 108-114)