简体   繁体   English

在GoLang中将Json数据映射到Html模板

[英]Map Json Data To Html Template In GoLang

I am looping through my API response and adding it to the html template like this, 我正在循环我的API响应并将其添加到这样的html模板,

 // Following sends same information as above to the browser as html
     t, err := template.New("TopMovies").Parse(`
      {{define "TopMovies"}}
        <html>
        <ul>
        {{$ImgUrl := "http://image.tmdb.org/t/p/w185" }}
        {{range $movies := .Results}}
        <li>{{$ImgUrl}}{{$movies.PosterPath}}</li>
        <li>{{$movies.Adult}}</li>
        <li>{{$movies.Overview}}</li>
        <li>{{$movies.ReleaseDate}}</li>
        <li>{{$movies.GenreIds}}</li>
        <li>{{$movies.Id}}</li>
        <li>{{$movies.OriginalTitle}}</li>
        <li>{{$movies.OriginalLanguage}}</li>
        <li>{{$movies.Title}}</li>
        <li>{{$ImgUrl}}{{$movies.BackdropPath}}</li>
        <li>{{$movies.Popularity}}</li>
        <li>{{$movies.VoteCount}}</li>
        <li>{{$movies.Video}}</li>
        <li>{{$movies.VoteAverage}}</li>
        {{end}}
        </ul>
        </html>
      {{end}}
      `)
    err = t.ExecuteTemplate(w, "T", p) // This writes the client response
}

I am under the impression I should be able to call this in my html templates like this, 我的印象是我应该可以在我这样的html模板中调用它,

{{.TopMovies}}

But when I run the app the data does not appear in the html page I am calling it in. What am I missing here? 但是当我运行应用程序时,数据不会显示在我调用它的html页面中。我在这里缺少什么?

I create a struct like this, 我创建了这样的结构,

//A Page structure
type Page struct {
  Title string
  TopMovies string
}

Then I create my handle like this, 然后我像这样创建我的手柄,

func TopMoviesHandler(w http.ResponseWriter, r *http.Request) {
   res, err := http.Get(url)
      if err != nil {
        panic(err)
      }
      defer res.Body.Close()

      body, err := ioutil.ReadAll(res.Body)
      if err != nil {
        panic(err)
      }
      var p Payload

      err = json.Unmarshal(body, &p)
      if err != nil {
        panic(err)
      }

  // Following sends same information as above to the browser as html
     t, err := template.New("TopMovies").Parse(`
      {{define "TopMovies"}}
        <html>
        <ul>
        {{$ImgUrl := "http://image.tmdb.org/t/p/w185" }}
        {{range $movies := .Results}}
        <li>{{$ImgUrl}}{{$movies.PosterPath}}</li>
        <li>{{$movies.Adult}}</li>
        <li>{{$movies.Overview}}</li>
        <li>{{$movies.ReleaseDate}}</li>
        <li>{{$movies.GenreIds}}</li>
        <li>{{$movies.Id}}</li>
        <li>{{$movies.OriginalTitle}}</li>
        <li>{{$movies.OriginalLanguage}}</li>
        <li>{{$movies.Title}}</li>
        <li>{{$ImgUrl}}{{$movies.BackdropPath}}</li>
        <li>{{$movies.Popularity}}</li>
        <li>{{$movies.VoteCount}}</li>
        <li>{{$movies.Video}}</li>
        <li>{{$movies.VoteAverage}}</li>
        {{end}}
        </ul>
        </html>
      {{end}}
      `)
    err = t.ExecuteTemplate(w, "T", p) // This writes the client response
}

Then in main.go 然后在main.go

   http.HandleFunc("/TopPicks", TopMoviesHandler)

TopPicks.html

{{define "TopPicks"}}
    {{template "header" .}}
    <div class="content">
    {{.TopMovies}}
    </div>
     {{template "footer" .}}
    {{end}}

What does work is this, 这是什么工作,

func aboutHandler(w http.ResponseWriter, r *http.Request) {
  display(w, "about", &Page{Title: "About"})
}

I can add a title to the page in the same way as I previously mentioned but using display() 我可以用与前面提到的相同的方式为页面添加标题但是使用display()

And in the html template 并在HTML模板中

<title>{{.Title}}</title>

How can I make this work for my json response? 我怎样才能为json响应做这项工作?

Looks like you are doing {{define "body"}} , but then asking ExecuteTemplate to execute "T" which isn't defined anywhere. 看起来你正在做{{define "body"}} ,但后来要求ExecuteTemplate执行“T”,它没有在任何地方定义。

I think you want: t.ExecuteTemplate(w, "body", p) 我想你想: t.ExecuteTemplate(w, "body", p)

That all said, if you just want to use multiple templates, you can do it by creating a master top level template, then parsing all the parts as sub templates. 总而言之,如果您只想使用多个模板,可以通过创建主顶级模板,然后将所有部件解析为子模板来实现。

Here's an example ( on Play ). 这是一个例子( 在Play上 )。

Easily changed to walk your file system and load all your templates, then you just execute the template matching the http.Request path. 轻松更改以遍历文件系统并加载所有模板,然后只需执行与http.Request路径匹配的模板。

package main

import "html/template"
import "os"
import "log"

var mainText = `
Normal page stuff
{{ template "_header_" . }}
{{ template "body" . }}
`

var bodyText = `
 Body has: {{ .Thing }}
`
var headerText = `
 I am header text
`

type Stuff struct {
    Thing string
}

func main() {
    t := template.New("everything")

    // parse all templates you may want
    template.Must(t.New("/").Parse(mainText))
    template.Must(t.New("_header_").Parse(headerText))
    template.Must(t.New("body").Parse(bodyText))

    if err := t.ExecuteTemplate(os.Stdout, "/", Stuff{"I am a thing"}); err != nil {
        log.Fatal("Failed to execute:", err)
    }
}

Ok, I think there were two problems with the original code. 好吧,我认为原始代码存在两个问题。

  1. Handler was calling wrong template 处理程序调用了错误的模板

func TopMoviesHandler(w http.ResponseWriter, r *http.Request) { ...snip original code... func TopMoviesHandler(w http.ResponseWriter,r * http.Request){...剪切原始代码......

err = t.ExecuteTemplate(w, "T", p) // This writes the client response

Should be 

err = t.ExecuteTemplate(w, "TopMovies", p) // This writes the client response
  1. Incorrect context was passed to nested template 将不正确的上下文传递给嵌套模板

In the html file there was this code 在html文件中有这个代码

{{define "TopPicks"}}
     {{template "header" .}}
     <div class="content">
          {{.TopMovies}}
          {{template "MyTemplate" . }}
     </div>
     {{template "footer" .}}
{{end}}

Which should be 应该是哪个

{{define "TopPicks"}}
     {{template "header" .}}
     <div class="content">
          {{.TopMovies}}
          {{template "MyTemplate" .TopMovies }}
     </div>
     {{template "footer" .}}
{{end}}

The reason was that you were trying to pass the main context to the nested template, versus just the json result the template was expecting. 原因是您尝试将主要上下文传递给嵌套模板,而不仅仅是模板所期望的json结果。

Original Answer 原始答案

I made a simple example of what I think you need to do. 我举了一个简单的例子,说明我认为你需要做什么。 Where I set the topMovies variable, this is where you would set the results from your api call. 在我设置topMovies变量的地方,您可以在此处设置api调用的结果。 I hope this helps to show you the sequence you need to follow a little bit better. 我希望这有助于向您展示您需要更好地遵循的顺序。

package main

import (
    "net/http"
    "text/template"
)

type movie struct {
    Title string
}

type page struct {
    Title     string
    TopMovies []movie
}

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
        w.Header().Add("Content Type", "text/html")

        templates := template.New("template")
        templates.New("Body").Parse(doc)
        templates.New("List").Parse(docList)

        topMovies := []movie{{Title: "Movie 1"}, {Title: "Movie 2"}, {Title: "Movie 3"}}

        page := page{Title: "My Title", TopMovies: topMovies}
        templates.Lookup("Body").Execute(w, page)

    })

    http.ListenAndServe(":8000", nil)
}

const docList = `
<ul >
    {{range .}}
    <li>{{.Title}}</li>
    {{end}}
</ul>
`

const doc = `
<!DOCTYPE html>
<html>
    <head><title>{{.Title}}</title></head>
    <body>
        <h1>Hello Templates</h1>
        {{template "List" .TopMovies}}
    </body>
</html>
`

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM