英文:
Golang Template Range (for loop) using JSON from WebSocket
问题
我正在使用Gorilla Websocket来更新一些HTML(img src,文本等);我是这样做的:
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
[...]
app, err := models.DB.SearchAppStore(ctx, stars, updatedWithin, 0)
myJson, err := json.Marshal(app)
err = c.WriteMessage(mt, myJson)
if err != nil {
log.Println("write:", err)
break
}
然后,我使用JavaScript来更新HTML数据:
ws.onmessage = function(evt) {
var d = JSON.parse(evt.data);
var app;
for (app = 0; app < 3; app++) {
document.getElementById("app-icon-" + app).src = d[app].ThumbnailURL;
document.getElementById("app-title-" + app).innerHTML = d[app].Title;
document.getElementById("app-compatibility-" + app).innerHTML = d[app].Compatibility;
}
};
然后,我手动输入HTML,如下所示:
<div class="app-section">
<div class="icon">
<img src="" id="app-icon-0">
</div>
<div class="details">
<h2 id="app-title-0"></h2>
<h5 id="app-compatibility-0"></h5>
</div>
</div>
你可以看到HTML中的0,我应该注意到它实际上更长,但我尽量只取相关部分。
当然,我不想手动输入HTML,因为这将使处理不同长度的情况变得困难(比如有时我想显示一百个应用程序,其他时候可能只有3个可用等等)。
我想这可能可以通过使用Golang的HTML {{range}}
函数来实现,但我无法弄清楚如何将其与来自Websockets的JSON数据集成在一起。
另一个可行的解决方案是在ws.onmessage
的循环中直接编写所有HTML,但我认为最好还是学习如何使用Golang的模板包来实现它。特别是因为它非常冗长,而且有很多类和ID。
在我看来,我需要获取JSON的长度(Object.keys(d).length;
),然后以某种方式将这个长度传递给{{range}}
,然后可以使用{{index}}
来遍历JSON对象。
但是,我还没有找到如何实现它的方法,也许这甚至不可能。如果有人能帮助我解决这个问题,我将非常感激。
英文:
I'm using Gorilla Websocket to update some HTML (img src, text, etc); I do this the following way:
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
[...]
app, err := models.DB.SearchAppStore(ctx, stars, updatedWithin, 0)
myJson, err := json.Marshal(app)
err = c.WriteMessage(mt, myJson)
if err != nil {
log.Println("write:", err)
break
}
Then I use javascript to update the HTML data this way:
ws.onmessage = function(evt) {
var d = JSON.parse(evt.data);
var app;
for (app = 0; app < 3; app++) {
document.getElementById("app-icon-" + app).src = d[app].ThumbnailURL;
document.getElementById("app-title-" + app).innerHTML = d[app].Title;
document.getElementById("app-compatibility-" + app).innerHTML = d[app].Compatibility;
}
};
And then I have manually typed the HTML this way:
<div class="app-section">
<div class="icon">
<img src="" id="app-icon-0">
</div>
<div class="details">
<h2 id="app-title-0"></h2>
<h5 id="app-compatibility-0"></h5>
</div>
</div>
You can see the 0 in the HTML 'id's, and I should note that it's much longer but I tried to only take the relevant parts..
I would of course like not to type HTML manually since it will make it difficult(/impossible) to deal with different lenghts (like maybe sometimes I want to display a hundred apps, other times maybe there only are 3 available, etc..)
I was thinking this might be able to be done using golang's HTML {{range}} function, but I can't figure out how to integrate it with json data from websockets..
Another solution that should be managable is to just write out all the HTML inside the JS for loop at ws.onmessage
, but I think it would be better if I learned how to do it using the golang template package.. Especially because it's really long and there are many classes/id's..
The way I see it, I need to get the length of the JSON (Object.keys(d).length;
), then somehow I need to pass this length inside {{range}} and then can use {{index}} to interate through the JSON object..
..but I haven't been able to figure out how to do it, maybe it's not even possible.. I would greatly appreciate any help with how this can be done..
答案1
得分: 1
一个简单的方法是在服务器上执行模板,并将生成的HTML发送到客户端,然后将HTML插入到页面中。
在包级别声明一个带有编译模板的变量。
该模板假设Execute的参数是一个包含字段ThumbnailURL、Title和Compatibility的结构体或映射的切片。
var t = template.Must(template.New("").Parse(`{{range .}}
<div class="icon">
<img src="{{.ThumbnailURL}}">
</div>
<div class="details">
<h2>{{.Title}}</h2>
<h5>{{.Compatibility}}</h5>
</div>{{end}}`))
在读取循环中执行模板。将HTML发送给客户端:
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
[...]
app, err := models.DB.SearchAppStore(ctx, stars, updatedWithin, 0)
var buf bytes.Buffer
if err := t.Execute(&buf, app); err != nil {
// 处理错误
}
err = c.WriteMessage(mt, buf.Bytes())
if err != nil {
log.Println("write:", err)
break
}
在页面上添加一个用于显示结果的div:
<div class="app-section"></div>
当接收到消息时,设置div的内部HTML:
ws.onmessage = function(evt) {
document.getElementById("app-section").innerHTML = evt.Data;
}
这个解决方案不使用JSON。
英文:
A simple approach is to execute a template on the server and send the resulting HTML to the client where the HTML is inserted into the page.
Declare package level variable with compiled template.
This template assumes that the argument to Execute is a slice of
structs or maps with fields ThumbnailURL, Title and Compatibility.
var t = template.Must(template.New("").Parse(`{{range .}}
<div class="icon">
<img src="{{.ThumbnailURL}}">
</div>
<div class="details">
<h2>{{.Title}}</h2>
<h5>{{.Compatibility}}</h5>
</div>{{end}}`))
Execute the template in your read loop. Send the HTML to the client:
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
]
[...]
app, err := models.DB.SearchAppStore(ctx, stars, updatedWithin, 0)
var buf bytes.Buffer
if err := t.Execute(&buf, app); err != nil {
// handle error
}
err = c.WriteMessage(mt, buf.Bytes())
if err != nil {
log.Println("write:", err)
break
}
Include a div for the results on the page:
<div class="app-section"></div>
Set the div's inner HTML when a message is received:
ws.onmessage = function(evt) {
document.getElementById("app-section").innerHTML = evt.Data;
}
This solution does not use JSON.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论