检查项目是否存在并且是真还是假

问题描述

在我的代码中,我向模板发送了一个结构体 ReturnedResult

type ReturnedResult struct {
    Result  bool   `json:"result"`
    Message string `json:"message"`
}

我希望模板:

  1. 检查是否有 Result 或 nil
  2. 如果有 Result 我想检查它是 true 还是 false

所以,我写了以下内容

{{with .Result}}
  {{if .Result}}
    <div id='foo'>
      <i class="far fa-thumbs-up"></i>If report not opened automatically,pls download from <a href={{.Message}}>here</a>
    </div>
    <script>
      url = `{{.Message}}`
      window.open(url,"_blank");
      setTimeout(function () {document.querySelector('#foo').style.display='none'},5000);
    </script>
  {{else}}
    <i class="fas fa-exclamation-triangle">{{.Message}}</i>>
    <script>
      setTimeout(function () {document.querySelector('#foo').style.display='none'},5000);
    </script>
  {{end}}
{{end}}

有时我将没有数据的模板称为 tmpl.Execute(w,nil),有时将数据称为 tmpl.Execute(w,webReturn)

没有数据的可以正常工作,但有数据的却无法正常工作,不知道出了什么问题。

如果需要,下面是我的完整代码

// go build -ldflags "-H=windowsgui"
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/IoUtil"
    "log"
    "net/http"
    "strings"
    "text/template"

    "github.com/zserge/lorca"
)

// ContactDetails ...
type ContactDetails struct {
    Email   string
    Subject string
    Message string
    Color1  []string
    Color2  []string
}

// ReturnedResult ...
type ReturnedResult struct {
    Result  bool   `json:"result"`
    Message string `json:"message"`
}

func index(w http.ResponseWriter,r *http.Request) {
    tmpl := template.Must(template.ParseFiles("forms.html"))
    if r.Method != http.MethodPost {
        tmpl.Execute(w,nil)
        return
    }

    r.ParseForm()
    fmt.Println(r.Form) // print information on server side.
    fmt.Println("path",r.URL.Path)
    fmt.Println("scheme",r.URL.Scheme)
    fmt.Println(r.Form["color1"][0])
    fmt.Println(r.Form["color1"][1])
    for k,v := range r.Form {
        fmt.Println("key:",k)
        fmt.Println("val:",strings.Join(v,""))
    }
    details := ContactDetails{
        Email:   r.FormValue("email"),Subject: r.FormValue("subject"),Message: r.FormValue("message"),Color1:  r.Form["color1"],Color2:  r.Form["color2"],}
    fmt.Printf("Post from website! r.PostFrom = %v\n",r.PostForm)
    fmt.Printf("Details = %v\n",details)

    //r.FormValue("username")
    fmt.Println()
    // do something with details
    sheetID := "AKfycbxfMucXOzX15tfU4errRSAa9IzuTRbHzvUdRxzzeYnNA8Ynz8LJuBuaMA/exec"
    url := "https://script.google.com/macros/s/" + sheetID + "/exec"
    bytesRepresentation,err := json.Marshal(details)
    if err != nil {
        log.Fatalln(err)
    }
    resp,err := http.Post(url,"application/json",bytes.NewBuffer(bytesRepresentation))
    if err != nil {
        log.Fatalln(err)
    }
    // read all response body
    data,_ := IoUtil.ReadAll(resp.Body)

    // close response body
    resp.Body.Close()

    webReturn := ReturnedResult{}
    if err := json.Unmarshal([]byte(data),&webReturn); err != nil {
        panic(err)
    }
    fmt.Println(webReturn.Message)

    webReturn.Message = strings.ReplaceAll(webReturn.Message,"&export=download","")
    //tmpl.Execute(w,struct{ Success bool }{webReturn.Result})
    tmpl.Execute(w,webReturn)
}

func main() {
    // Start Host goroutine
    go func() {
        http.Handle("/static/",http.StripPrefix("/static/",http.FileServer(http.Dir("./public"))))
        http.HandleFunc("/",index)
        http.ListenAndServe(":8090",nil)
    }()

    // Start UI
    ui,err := lorca.New("http://localhost:8090/index","",1200,800)
    if err != nil {
        log.Fatal(err)
    }
    defer ui.Close()

    <-ui.Done()
}

模板;

<title>Form Submittal</title>
<style>
  body {
      font-family: Ubuntu,"times new roman",times,roman,serif;
  }
</style>
<link href="http://localhost:8090/static/fontawesome-free-5.15.2-web/css/all.css" rel="stylesheet"> <!--load all styles -->
<!-- link rel="stylesheet" href="http://localhost:8090/styles/MaterialDesign-Webfont-master/css/materialdesignicons.min.css" -->

<script type="module" src="http://localhost:8090/static/node_modules/@mdi/js/mdi.js"></script>
<script type="module">
 // import {mdi-home} from "./node_modules/@mdi/js/mdi.js";
 // alert(a);
</script>
<script>
  //import { mdi-home } from '/MaterialDesign-JS-master/mdi.js';
  function deleteRow(row) {
    var i = row.parentNode.parentNode.rowIndex - 2; // this -> td -> tr // -2 because the first 2 rows are used for header
    var tbl = document.querySelector('tbody');
    if(tbl && tbl.rows.length > 1) {
      tbl.deleteRow(i); 
      Array.from(tbl.rows).forEach((row,index) => {
        row.cells[0].innerHTML = index + 1;
      });
    }
  } 

  function insRow(row) {
    var i = row.parentNode.parentNode.rowIndex - 2; // this -> td -> tr // -2 because the first 2 rows are used for header
    var tbl = document.querySelector('tbody');
    var row = document.createElement('tr');
    row.innerHTML=`
      <th></th>
      <td><input size=25 type="text" name="color1" /></td>
      <td><input size=25 type="text" name="color2" ></td>
      <td><i class="fas fa-edit" onclick="insRow(this)"></i></td>
      <td><i class="fas fa-eraser" onclick="deleteRow(this)"></i></td>
    `;
    var len = tbl.rows.length;
    row.cells[0].innerHTML = len + 1;
    tbl.insertBefore(row,tbl.children[i+1]);
    Array.from(tbl.rows).forEach((row,index) => {
      row.cells[0].innerHTML = index + 1;
    });
    //tbl.appendChild(row);
  }
</script>
<h1>Contact</h1>
Bob lives in a <span class="mdi mdi-home"></span>.

<form method="POST">
    <label>Email:</label><br />
    <input type="text" name="email"><br />
    <label>Subject:</label><br />
    <input type="text" name="subject"><br />
    <label>Message:</label><br />
    <textarea name="message"></textarea><br />

    <table>
      <caption>Monthly savings</caption>
      <thead>
        <tr>
          <th colspan="5">The table header</th>
        </tr>
        <tr>
          <th>SN</td>
          <th>PO number</td>
          <th>PO invoice value</td>
          <th colspan="2">Action</td>
        </tr>
      </thead>
      <tbody >
        <tr>
          <th>1</th>
          <td><input size=25 type="text" name="color1" /></td>
          <td><input size=25 type="text" name="color2" /></td>
          <td colspan="2"><i class="fas fa-edit" onclick="insRow(this)"></i></td>
        </tr>
      </tbody>
      <tfoot>
        <tr>
          <th colspan="5">The table footer</th>
        </tr>
      </tfoot>
    </table>

   <input type="submit">
</form>
{{with .Message}}
  {{if .Result}}
    <div id='foo'>
      <i class="far fa-thumbs-up"></i>If report not opened automatically,5000);
    </script>
  {{end}}
{{end}}

解决方法

template.Execute() 返回一个 error检查:

if err := tmpl.Execute(w,webReturn); err != nil {
    // Handle error:
    log.Printf("Template error: %v",err)
    return
}

这是一个最小的可重现示例:

type ReturnedResult struct {
    Result  bool
    Message string
}

func main() {
    t := template.Must(template.New("").Parse(src))

    if err := t.Execute(os.Stdout,nil); err != nil {
        panic(err)
    }

    p := ReturnedResult{Result: false,Message: "a"}
    if err := t.Execute(os.Stdout,p); err != nil {
        panic(err)
    }

    p = ReturnedResult{Result: true,p); err != nil {
        panic(err)
    }
}

const src = `{{with .Message}}
  {{if .Result}}
    Message with true result
  {{else }}
    Message with false result
  {{end}}
{{end}}
`

Go Playground 上测试,输出为:

  panic: template: :2:7: executing "" at <.Result>: can't evaluate field Result in type string

goroutine 1 [running]:
main.main()
    /tmp/sandbox993188219/prog.go:22 +0x226

问题在于 {{with}} 操作设置了点,因此在 {{with}} 点内将表示 Message 字段,该字段显然没有 .Result 字段(它不是结构体)。

要进行测试(而不是更改点),请使用简单的 {{if}}

{{if .Message}}
  {{if .Result}}
    Message with true result
  {{else }}
    Message with false result
  {{end}}
{{end}}

使用此模板,输出将是(在 Go Playground 上尝试):

<empty output for the nil param>

Message with false result

Message with true result