admin管理员组

文章数量:1279115

I am using the Echo framework in Golang to serve HTML templates, but I have an issue where the title updates correctly. However, the content remains the same for both the home (/) and about (/about) pages.

When I navigate to /about, the title changes to "About | Application", but the content is still the same as the home page (/) instead of showing the correct about page content.

Project Structure

/app
  /handlers
    home.go
    about.go
  /views
    renderer.go
  /templates
    /layouts
      main.html
    /pages
      index.html
      about.html
  main.go

Code Implementation main.go (Entry Point)

package main

import (
    "app/handlers"
    "app/views"

    "github/labstack/echo/v4"
    "github/labstack/echo/v4/middleware"
)

func main() {
    e := echo.New()

    e.Use(middleware.Logger())
    e.Use(middleware.Recover())

    e.Renderer = views.NewRenderer()

    e.GET("/", handlers.Home)
    e.GET("/about", handlers.About)

    e.Static("/static", "static")

    e.Logger.Fatal(e.Start(":8080"))
}

views/renderer.go (Template Renderer)

package views

import (
    "html/template"
    "io"
    "path/filepath"
    "strings"

    "github/labstack/echo/v4"
)

type TemplateRenderer struct {
    templates *template.Template
}

func NewRenderer() *TemplateRenderer {
    funcMap := template.FuncMap{
        "dict": func(values ...interface{}) map[string]interface{} {
            if len(values)%2 != 0 {
                panic("invalid dict call")
            }
            dict := make(map[string]interface{}, len(values)/2)
            for i := 0; i < len(values); i += 2 {
                key, ok := values[i].(string)
                if !ok {
                    panic("dict keys must be strings")
                }
                dict[key] = values[i+1]
            }
            return dict
        },
    }

    tmpl := template.New("").Funcs(funcMap)

    layoutGlob := filepath.Join("templates", "layouts", "*.html")
    pagesGlob := filepath.Join("templates", "pages", "*.html")

    tmpl = template.Must(tmpl.ParseGlob(layoutGlob))
    tmpl = template.Must(tmpl.ParseGlob(pagesGlob))

    normalizedTemplates := template.New("").Funcs(funcMap)
    for _, t := range tmpl.Templates() {
        if t.Tree == nil || t.Tree.Root == nil {
            continue
        }
        name := t.Name()
        if strings.HasPrefix(name, "pages/") {
            name = strings.TrimPrefix(name, "pages/")
        }
        name = strings.TrimSuffix(name, ".html")
        _, err := normalizedTemplates.New(name).Parse(t.Tree.Root.String())
        if err != nil {
            panic("Failed to normalize template names: " + err.Error())
        }
    }

    return &TemplateRenderer{
        templates: normalizedTemplates,
    }
}

func (t *TemplateRenderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
    return t.templates.ExecuteTemplate(w, name, data)
}

handlers/home.go

package handlers

import (
    "net/http"

    "github/labstack/echo/v4"
)

func Home(c echo.Context) error {
    return c.Render(http.StatusOK, "index", map[string]interface{}{})
}

handlers/about.go

package handlers

import (
    "net/http"

    "github/labstack/echo/v4"
)

func About(c echo.Context) error {
    return c.Render(http.StatusOK, "about", map[string]interface{}{})
}

Templates

templates/layouts/main.html (Layout)

{{ define "layout" }}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ block "title" . }}{{ if .title }}{{ .title }} | Application{{ else }}Application{{ end }}{{ end }}</title>
    <link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
    <nav>
        <a href="/">Home</a> | <a href="/about">About</a>
    </nav>
    <main>
        {{ template "content" . }}
    </main>
</body>
</html>
{{ end }}

templates/pages/index.html

{{ template "layout" (dict "title" "Home") }}

{{ define "content" }}
    <h1>Welcome to the Home Page</h1>
    <p>This is a simple multi-page app with Echo.</p>
{{ end }}

templates/pages/about.html

{{ template "layout" (dict "title" "About") }}

{{ define "content" }}
    <h1>About</h1>
    <p>This is a simple multi-page app with Echo.</p>
{{ end }}

Expected Behavior / should render index.html inside layout/main.html. /about should render about.html inside layout/main.html.

Actual Behavior / works as expected. /about only updates the title but keeps the content from / (Home Page).

Possible Issue I suspect that {{ template "layout" (dict "title" "About") }} in about.html is calling layout directly and rendering "index.html" content instead of its own.

I am using the Echo framework in Golang to serve HTML templates, but I have an issue where the title updates correctly. However, the content remains the same for both the home (/) and about (/about) pages.

When I navigate to /about, the title changes to "About | Application", but the content is still the same as the home page (/) instead of showing the correct about page content.

Project Structure

/app
  /handlers
    home.go
    about.go
  /views
    renderer.go
  /templates
    /layouts
      main.html
    /pages
      index.html
      about.html
  main.go

Code Implementation main.go (Entry Point)

package main

import (
    "app/handlers"
    "app/views"

    "github/labstack/echo/v4"
    "github/labstack/echo/v4/middleware"
)

func main() {
    e := echo.New()

    e.Use(middleware.Logger())
    e.Use(middleware.Recover())

    e.Renderer = views.NewRenderer()

    e.GET("/", handlers.Home)
    e.GET("/about", handlers.About)

    e.Static("/static", "static")

    e.Logger.Fatal(e.Start(":8080"))
}

views/renderer.go (Template Renderer)

package views

import (
    "html/template"
    "io"
    "path/filepath"
    "strings"

    "github/labstack/echo/v4"
)

type TemplateRenderer struct {
    templates *template.Template
}

func NewRenderer() *TemplateRenderer {
    funcMap := template.FuncMap{
        "dict": func(values ...interface{}) map[string]interface{} {
            if len(values)%2 != 0 {
                panic("invalid dict call")
            }
            dict := make(map[string]interface{}, len(values)/2)
            for i := 0; i < len(values); i += 2 {
                key, ok := values[i].(string)
                if !ok {
                    panic("dict keys must be strings")
                }
                dict[key] = values[i+1]
            }
            return dict
        },
    }

    tmpl := template.New("").Funcs(funcMap)

    layoutGlob := filepath.Join("templates", "layouts", "*.html")
    pagesGlob := filepath.Join("templates", "pages", "*.html")

    tmpl = template.Must(tmpl.ParseGlob(layoutGlob))
    tmpl = template.Must(tmpl.ParseGlob(pagesGlob))

    normalizedTemplates := template.New("").Funcs(funcMap)
    for _, t := range tmpl.Templates() {
        if t.Tree == nil || t.Tree.Root == nil {
            continue
        }
        name := t.Name()
        if strings.HasPrefix(name, "pages/") {
            name = strings.TrimPrefix(name, "pages/")
        }
        name = strings.TrimSuffix(name, ".html")
        _, err := normalizedTemplates.New(name).Parse(t.Tree.Root.String())
        if err != nil {
            panic("Failed to normalize template names: " + err.Error())
        }
    }

    return &TemplateRenderer{
        templates: normalizedTemplates,
    }
}

func (t *TemplateRenderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
    return t.templates.ExecuteTemplate(w, name, data)
}

handlers/home.go

package handlers

import (
    "net/http"

    "github/labstack/echo/v4"
)

func Home(c echo.Context) error {
    return c.Render(http.StatusOK, "index", map[string]interface{}{})
}

handlers/about.go

package handlers

import (
    "net/http"

    "github/labstack/echo/v4"
)

func About(c echo.Context) error {
    return c.Render(http.StatusOK, "about", map[string]interface{}{})
}

Templates

templates/layouts/main.html (Layout)

{{ define "layout" }}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ block "title" . }}{{ if .title }}{{ .title }} | Application{{ else }}Application{{ end }}{{ end }}</title>
    <link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
    <nav>
        <a href="/">Home</a> | <a href="/about">About</a>
    </nav>
    <main>
        {{ template "content" . }}
    </main>
</body>
</html>
{{ end }}

templates/pages/index.html

{{ template "layout" (dict "title" "Home") }}

{{ define "content" }}
    <h1>Welcome to the Home Page</h1>
    <p>This is a simple multi-page app with Echo.</p>
{{ end }}

templates/pages/about.html

{{ template "layout" (dict "title" "About") }}

{{ define "content" }}
    <h1>About</h1>
    <p>This is a simple multi-page app with Echo.</p>
{{ end }}

Expected Behavior / should render index.html inside layout/main.html. /about should render about.html inside layout/main.html.

Actual Behavior / works as expected. /about only updates the title but keeps the content from / (Home Page).

Possible Issue I suspect that {{ template "layout" (dict "title" "About") }} in about.html is calling layout directly and rendering "index.html" content instead of its own.

Share Improve this question asked Feb 24 at 4:51 Ali ZainAli Zain 416 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

about.html and index.html both call {{ template "layout" (dict "title" "About") }}. layout.html doesn't know which specific page is being rendered, so we should pass content block correctly, we can define content before including the layout:

In your about.html:

{{ define "content" }}
    <h1>About</h1>
    <p>This is a simple multi-page app with Echo.</p>
{{ end }}
{{ template "layout" (dict "title" "About" "content" .) }}

in your index.html:

{{ define "content" }}
    <h1>Welcome to the Home Page</h1>
    <p>This is a simple multi-page app with Echo.</p>
{{ end }}
{{ template "layout" (dict "title" "Home" "content" .) }}

Update {{ template "content" . }} to {{ .content }} in main.html:

<main>
    {{ .content }}
</main>

本文标签: htmlEcho Golang Template Issue Content Not Changing on Different RoutesStack Overflow