Как передать несколько данных в шаблон Go?

Я хочу передать два объекта данных в шаблон Go. Один из них — результат запроса MongoDB, а другой — целочисленный массив.

Запрос MongoDB: -

var results []User
sess, db := GetDatabase()
defer sess.Close()
c := db.C("user")
err := c.Find(nil).All(&results)

Я хочу отправить «результат» и массив int через следующий код

GetTemplate("list").Execute(w,???????)

Если есть только результат db, мы могли бы использовать его как

GetTemplate("list").Execute(w,results)

и в шаблоне мы могли бы получить к нему доступ {{.Name}} и т. д. (где Name - это поле структуры []User)

Подскажите, пожалуйста, как передать эти данные и как получить к ним доступ в шаблоне.


person Arjun Ajith    schedule 05.02.2016    source источник


Ответы (2)


Вы можете передать только одно значение, но это значение может быть составным значением из нескольких значений, например. структура, карта или срез. Поэтому просто оберните несколько данных, предназначенных для шаблона, в struct или map.

Пример с struct:

type Data struct {
    Results []User // Must be exported!
    Other   []int  // Must be exported!
}

data := &Data{results, []int{1, 2, 3}}
if err := GetTemplate("list").Execute(w, data); err != nil {
    // Handle error
}

Также обратите внимание, что новый именованный тип не требуется, вы также можете использовать литерал анонимной структуры, который может выглядеть так:

data := struct {
    Results []User // Must be exported!
    Other   []int  // Must be exported!
}{results, []int{1, 2, 3}}

Пример с map:

m := map[string]interface{}{
    "Results": results,
    "Other":   []int{1, 2, 3},
}

if err := GetTemplate("list").Execute(w, m); err != nil {
    // Handle error
}

Обратите внимание, что при использовании карты не требуется использовать заглавные буквы string в качестве ключей, например. вы могли бы также использовать "results" и "other" (но, на мой взгляд, лучше использовать ключи с заглавными начальными буквами, если вы когда-нибудь в будущем будете переходить на struct, у вас будет меньше исправлений).

В обоих случаях вы можете ссылаться на результаты []User с помощью {{.Results}} и на дополнительный срез int с помощью {{.Other}}.

Так, например, для диапазона пользователей:

{{range .Results}}
    User name:{{.Name}}
{{end}}

Пример с slice:

s := []interface{}{
    results,
    []int{1, 2, 3},
}

if err := GetTemplate("list").Execute(w, s); err != nil {
    // Handle error
}

Это менее читаемое, но жизнеспособное решение. В шаблоне вы должны индексировать данные шаблона, чтобы получить «индивидуальные» значения, например:

{{range index . 0}}
    User name:{{.Name}}
{{end}}

Other: {{index . 1}}

Попробуйте его на Go Playground.

Другие способы...

Есть и другие "теоретические" способы, но я бы не стал их использовать только потому, что они работают.

Например, вы также можете передать канал, из которого будут получены значения.

Еще одним решением может быть регистрация пользовательских функций, которые при вызове будет возвращать значения.

person icza    schedule 05.02.2016

Вы должны определить структуру, заполненную запросом результатов базы данных, а затем назначить эту структуру методу Execute.

tmpl.Execute требуется интерфейс Writer и struct

type Inventory struct {
    Material string
    Count    uint
}

items := Inventory{"trouser", 1}    
if err := GetTemplate("list").Execute(w, items); err != nil {
    // ... do your work
}
person Endre Simo    schedule 05.02.2016