首页 > 解决方案 > 检查项目是否存在并且是真还是假

问题描述

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

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

我希望模板:

  1. 检查是否有aResult或nil
  2. 如果有一个Result我想检查它是否是truefalse

所以,我写了以下内容:

{{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, 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}}

标签: gostructgo-templates

解决方案


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, Message: "a"}
    if err := t.Execute(os.Stdout, 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

推荐阅读