Using html/template I am trying to populate a date field in an HTML form from a time.Time
type of field using template.FuncMap
but it is not working for me.
The following code is working,
type Task struct {
ID int
ProjectID int
Description string
StartDate time.Time
Duration float32
}
type ProjectTaskData struct {
ProjectID int
ProjectName string
TaskDetails Task
FormattedStartDate string // this field is a hack/workaround for me
}
My trimmed down main
function,
func main() {
db := GetConnection()
r := mux.NewRouter()
// other handlers here are removed
r.HandleFunc("/project/{project-id}/add-task", AddTask(db))
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("static/"))))
http.ListenAndServe(":8080", r)
}
The AddTask
function,
func AddTask(db *sql.DB) func(w http.ResponseWriter, r *http.Request) {
//tmpl := template.Must(template.New("").Funcs(template.FuncMap{
// "startdate": func(t time.Time) string { return t.Format("2006-01-02") },
//}).ParseFiles("static/add_task.html"))
tmpl := template.Must(template.ParseFiles("static/add_task.html"))
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
projectID, err := strconv.Atoi(vars["project-id"])
if err != nil {
log.Fatal(err)
}
var projectName string
var projectStartDate time.Time
err = db.QueryRow(`select name, start_date from projects where id = ?`, projectID).Scan(&projectName, &projectStartDate)
switch {
case err == sql.ErrNoRows:
log.Printf("No project with id %d\n", projectID)
return
case err != nil:
log.Fatalf("Query error: %v\n", err)
default:
log.Printf("Got project %v with id %d\n", projectName, projectID)
}
if r.Method != http.MethodPost {
data := ProjectTaskData{
ProjectID: projectID,
ProjectName: projectName,
TaskDetails: Task{
ProjectID: projectID,
Description: "",
StartDate: projectStartDate,
Duration: 1,
},
FormattedStartDate: projectStartDate.Format(time.DateOnly),
}
tmpl.Execute(w, data)
return
}
// rest of code handling the post action here
http.Redirect(w, r, "/project/"+fmt.Sprint(projectID)+"/tasks", http.StatusFound)
}
}
In the add_task.html
, if I put the following place-holder, it is able to populate the start date when I hit http://localhost:8080/project/1/add-task,
<input type="date" id="start_date" name="start_date" value="{{.FormattedStartDate}}">
However, if I replace the below first line in AddTask(),
tmpl := template.Must(template.ParseFiles("static/add_task.html"))
with the below one,
tmpl := template.Must(template.New("").Funcs(template.FuncMap{
"startdate": func(t time.Time) string { return t.Format("2006-01-02") },
}).ParseFiles("static/add_task.html"))
and if I change the add_task.html as below,
<input type="date" id="start_date" name="start_date" value="{{.TaskDetails.StartDate | startdate}}">
I get an empty response when I hit http://localhost:8080/project/1/add-task (but I get 200 OK)
I also referred the below question but wasn't successful,
As mentioned by @icza in the comment, receiving the error from Template.Execute()
revealed the issue.
I got the error,
template: "" is an incomplete or empty template
Referring to the answer at https://stackoverflow.com/a/49043639/8813473, I changed the template.New("")
call to template.New("add_task.html")
to resolve the issue.
The final code looks like below,
tmpl := template.Must(template.New("add_task.html").Funcs(template.FuncMap{
"startdate": func(t time.Time) string { return t.Format("2006-01-02") },
}).ParseFiles("static/add_task.html"))