英文:
How to execute multiple variables in HTML Go Template?
问题
我尝试查看其他问题,但它们似乎不能解决我的情况。
我基本上需要在我的HTML页面上有两个if语句,但是每当我触发第二个tmpl.Execute()时,我实际上会在这些if语句中嵌入相同的页面。
这是我试图使其工作的函数:
func RemoveVehicle(w http.ResponseWriter, r *http.Request) {
	conditionsMap := map[string]interface{}{}
	username, _ := ExtractTokenUsername(r)
	if username != "" {
		conditionsMap["Username"] = username
	}
	t, err := template.ParseFiles("remove.html")
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	if r.Method != http.MethodPost {
		t.Execute(w, conditionsMap) //在这里,我试图检查用户是否已登录,如果没有,则返回一个触发else语句的false布尔值
		return
	}
	db, err := sql.Open("mysql", "root:*******@tcp(127.0.0.1:3306)/my_db")
	if err != nil {
		fmt.Println("Connection Failed.")
		panic(err.Error())
	}
	defer db.Close()
	var car Vehicle
	sqlStatement := `SELECT * FROM Vehicle`
	rows, err := db.Query(sqlStatement)
	if err != nil {
		panic(err)
	}
	defer rows.Close()
	var carSlice []Vehicle
	for rows.Next() {
		rows.Scan(&car.Id, &car.Date, &car.Brand, &car.Model, &car.Mileage, &car.Year, &car.rented, &car.Dayrate)
		carSlice = append(carSlice, car)
	}
	if r.Method != http.MethodPost {
		t.Execute(w, carSlice) //然后在这里,我试图用表中的几行填充表单选择
		return
	}
	var id_ = r.FormValue("select")
	fmt.Println(id_)
	stmt, e := db.Prepare("DELETE FROM vehicle WHERE id=?")
	ErrorCheck(e)
	stmt.Exec(id_)
}
我已经注释掉了我试图同时使其工作的两个部分,但它们单独工作。
这是相关的HTML代码:
{{if .Username}}
<div><img src="images/kogdpilnmzhz9rhzceo2.png" alt="" width="65" height="65" class="addV_label"/></div>
<hr style="height:5px">
<form action="/remove" method="POST" source="custom" name="form">
   <input type="hidden" name="xss-token" value=""/>
   <div class="form-group">
      <div>
         <label class="addV_label">Select Vehicle </label>
         <select name="select" class="form-control loginInput2" required="required">
            {{range .}}
            <option value="{{.Id}}">{{.Brand}} {{.Model}} ({{.Year}}), {{.Mileage}} miles | £{{.Dayrate}}/pd</option>
            {{end}}
         </select>
      </div>
   </div>
   <div>
      <button class="btn-block frgt_1 btn addV_btn" type="submit" value="remove">REMOVE</button>
   </div>
</form>
{{else}}
<p> Access Denied, please login.<a href="/login">Login</a></p>
{{end}}
我尝试使用一个结构体,但carSlice已经是一个结构体,而conditionMap是一个映射。
解决这种情况的最佳方法是什么?
英文:
I've tried looking at the other questions, and they don't seem to help my situation.
I essentially need to have 2 if statements on my HTML page, but whenever I trigger the second tmpl.Execute() I essentially get the same page embedded within those if statements.
Here is a function that I am trying to get working:
func RemoveVehicle(w http.ResponseWriter, r *http.Request) {
conditionsMap := map[string]interface{}{}
username, _ := ExtractTokenUsername(r)
if username != "" {
conditionsMap["Username"] = username
}
t, err := template.ParseFiles("remove.html")
if err != nil {
http.Error(w, err.Error(), 500)
return
}
if r.Method != http.MethodPost {
t.Execute(w, conditionsMap) //Here I am trying to check to see if the user is logged in, and if not to return a false boolean that will trigger the else statement
return
}
db, err := sql.Open("mysql", "root:*******@tcp(127.0.0.1:3306)/my_db")
if err != nil {
fmt.Println("Connection Failed.")
panic(err.Error())
}
defer db.Close()
var car Vehicle
sqlStatement := `SELECT * FROM Vehicle`
rows, err := db.Query(sqlStatement)
if err != nil {
panic(err)
}
defer rows.Close()
var carSlice []Vehicle
for rows.Next() {
rows.Scan(&car.Id, &car.Date, &car.Brand, &car.Model, &car.Mileage, &car.Year, &car.rented, &car.Dayrate)
carSlice = append(carSlice, car)
}
if r.Method != http.MethodPost {
t.Execute(w, carSlice) // Then here I am trying to populate the form select with a few rows from a table
return
}
var id_ = r.FormValue("select")
fmt.Println(id_)
stmt, e := db.Prepare("DELETE FROM vehicle WHERE id=?")
ErrorCheck(e)
stmt.Exec(id_)
}
I have commented out the 2 parts that I am trying to get working simultaneously, but they work individually.
Here is the relevant HTML:
                        {{if .Username}}
<div><img src="images/kogdpilnmzhz9rhzceo2.png" alt="" width="65" height="65" class="addV_label"/></div>
<hr style="height:5px">
<form action="/remove" method="POST" source="custom" name="form">
<input type="hidden" name="xss-token" value=""/>
<div class="form-group">
<div>
<label class="addV_label">Select Vehicle&nbsp;</label>
<select name="select" class="form-control loginInput2" required="required">
{{range .}}
<option value="{{.Id}}">{{.Brand}} {{.Model}} ({{.Year}}), {{.Mileage}} miles | £{{.Dayrate}}/pd</option>
{{end}}
</select>
</div>
</div>
<div>
<button class="btn-block frgt_1 btn addV_btn" type="submit" value="remove">REMOVE</button>
</div>
</form>
{{else}}
<p> Access Denied, please login.<a href="/login">Login</a></p>
{{end}}
I've tried to use a struct, but the carSlice is already a struct and conditionMap is a map.
What would be the best solution to tackling this situation?
答案1
得分: 2
首先,建议在程序启动时只初始化*template.Template类型和*sql.DB连接池一次。这两种类型都可以安全地并发使用,因此可以同时被多个处理程序使用。
var (
	removeTemplate *template.Template
	db             *sql.DB
)
func init() {
	var err error
	removeTemplate, err = template.ParseFiles("remove.html")
	if err != nil {
		panic(err)
	}
	db, err = sql.Open("mysql", "root:*******@tcp(127.0.0.1:3306)/my_db")
	if err != nil {
		panic(err)
	} else if err := db.Ping(); err != nil {
		panic(err)
	}
}
现在你的处理程序可以如下所示:
func RemoveVehicle(w http.ResponseWriter, r *http.Request) {
    // 检查用户是否已登录
	username, _ := ExtractTokenUsername(r)
	if len(username) == 0 {
        // 如果没有登录,渲染没有数据的模板,这将显示模板中的“请登录”部分
		if err := removeTemplate.Execute(w, nil); err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}
    switch r.Method {
	// 如果方法是GET,显示可用车辆列表
	case http.MethodGet:
		// 从数据库中选择车辆
		rows, err := db.Query(`SELECT * FROM Vehicle`)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		defer rows.Close()
		// 扫描行
		var vehicles []Vehicle
		for rows.Next() {
			var v Vehicle
			err := rows.Scan(&v.Id, &v.Date, &v.Brand, &v.Model, &v.Mileage, &v.Year, &v.rented, &v.Dayrate)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			vehicles = append(vehicles, v)
		}
		if err := rows.Err(); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		// 现在使用刚刚从数据库中检索到的数据渲染模板
		data := map[string]interface{}{
			"Username": username,
			"Vehicles": vehicles,
		}
		if err := removeTemplate.Execute(w, data); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	// 如果方法是POST,删除车辆
	case http.MethodPost:
		var id = r.FormValue("select")
		if _, err := db.Exec("DELETE FROM vehicle WHERE id=?", id); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}
在模板中,由处理程序传递的数据是一个带有Username和Vehicles键的映射,你需要对.Vehicles进行range迭代,而不仅仅是.。
{{if .Username}}
<div><img src="images/kogdpilnmzhz9rhzceo2.png" alt="" width="65" height="65" class="addV_label"/></div>
<hr style="height:5px">
<form action="/remove" method="POST" source="custom" name="form">
	<input type="hidden" name="xss-token" value=""/>
	<div class="form-group">
		<div>
			<label class="addV_label">Select Vehicle </label>
			<select name="select" class="form-control loginInput2" required="required">
				{{range .Vehicles}}
				<option value="{{.Id}}">{{.Brand}} {{.Model}} ({{.Year}}), {{.Mileage}} miles | £{{.Dayrate}}/pd</option>
				{{end}}
			</select>
		</div>
	</div>
	<div>
		<button class="btn-block frgt_1 btn addV_btn" type="submit" value="remove">REMOVE</button>
	</div>
</form>
{{else}}
<p> Access Denied, please login.<a href="/login">Login</a></p>
{{end}}
英文:
First off, it is recommended to initialize the *template.Template types and the *sql.DB connection pool only once, during program start up. Both types are safe for concurrent use and can therefore be used by multiple handlers simultaneously.
var (
	removeTemplate *template.Template
	db             *sql.DB
)
func init() {
	var err error
	removeTemplate, err = template.ParseFiles("remove.html")
	if err != nil {
		panic(err)
	}
	db, err = sql.Open("mysql", "root:*******@tcp(127.0.0.1:3306)/my_db")
	if err != nil {
		panic(err)
	} else if err := db.Ping(); err != nil {
		panic(err)
	}
}
Now your handler can look something like the following:
func RemoveVehicle(w http.ResponseWriter, r *http.Request) {
    // check if the user is logged in
	username, _ := ExtractTokenUsername(r)
	if len(username) == 0 {
        // if not, render the template with no data, this
        // will show the "please login" part of your template
		if err := removeTemplate.Execute(w, nil); err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}
    switch r.Method {
	// if the method is GET, show the list of vehicles available
	case http.MethodGet:
		// select vehicles from db
		rows, err := db.Query(`SELECT * FROM Vehicle`)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		defer rows.Close()
		// scan rows
		var vehicles []Vehicle
		for rows.Next() {
			var v Vehicle
			err := rows.Scan(&v.Id, &v.Date, &v.Brand, &v.Model, &v.Mileage, &v.Year, &v.rented, &v.Dayrate)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			vehicles = append(vehicles, v)
		}
		if err := rows.Err(); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		// now render the template with the data
        // that you just retrieved from the database
		data := map[string]interface{}{
			"Username": username,
			"Vehicles": vehicles,
		}
		if err := removeTemplate.Execute(w, data); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	// if the method is POST, delete the vehicle
	case http.MethodPost {
		var id = r.FormValue("select")
		if _, err := db.Exec("DELETE FROM vehicle WHERE id=?", id); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}
And in your template, since a data passed in by the handler is a map with Username and Vehicles keys, you need to range over .Vehicles and not just the ..
{{if .Username}}
<div><img src="images/kogdpilnmzhz9rhzceo2.png" alt="" width="65" height="65" class="addV_label"/></div>
<hr style="height:5px">
<form action="/remove" method="POST" source="custom" name="form">
	<input type="hidden" name="xss-token" value=""/>
	<div class="form-group">
		<div>
			<label class="addV_label">Select Vehicle&nbsp;</label>
			<select name="select" class="form-control loginInput2" required="required">
				{{range .Vehicles}}
				<option value="{{.Id}}">{{.Brand}} {{.Model}} ({{.Year}}), {{.Mileage}} miles | £{{.Dayrate}}/pd</option>
				{{end}}
			</select>
		</div>
	</div>
	<div>
		<button class="btn-block frgt_1 btn addV_btn" type="submit" value="remove">REMOVE</button>
	</div>
</form>
{{else}}
<p> Access Denied, please login.<a href="/login">Login</a></p>
{{end}}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论