我的场景:一个站点显示来自持久后端的一堆行。用户可以向这些行添加 ajax 样式(即不离开当前站点。)当提交按钮被点击时,我希望在不加载另一个页面的情况下发生两件事:
- 新行应作为 JSON 对象发送到服务器并添加到那里的数据库中。
- 新行应立即添加到表中并可见。
此外,
- 当用户刷新站点时,表格应该与添加一堆行后的外观相同。错误处理很棘手,但可能,而不是我的(当前)问题。
我的实现大致如下:
getHomeR = do
records ← runDB $ selectList …
defaultLayout $ do
$(widgetFile "tableWidget")
关键部分是,我不想将这些行渲染到 HTML 服务器端,我希望这发生在客户端,因为客户端必须 能够渲染它们!(并维护以完全相同的方式呈现完全相同的东西的客户端和服务器端代码,这让我觉得这是一种容易出错的方法。)
所以相反,我records
通过 julius 插值将 JS 变量放入:
var records = #{toJSON records}; // the Haskell value containing the data.
renderRow = function(jsonObject) { … }
appendRowToTable = function(row) { … }
$(document).ready(function() {
$.each(records, function(i,v) {
appendRowToTable(renderRow(v));
});
});
这是我能想到的最优雅的解决方案。它避免了必须进行单独的ajax 调用来读取记录,即我知道我可以添加一条从数据库中获取新记录并将其添加到 JS 的路由,但这让我觉得效率低下:它涉及到一轮- 我想避免的旅行。相反,JS 和 HTML 是在第一个请求上构建的,并且所有内容都以一堆快乐的方式发送过来。现在问题发生在重新加载时:
虽然records
Haskell 变量的内容可能会在页面加载之间发生变化,但不会重新评估插值。Yesod 假设 Julius 文件,包括其所有与 IO 相关的插值,保持不变,但事实并非如此。我最终得到了一个records
与 Haskell 变量的内容不同的 JavaScript 变量,这对我来说是不可接受的。我需要触摸 Julius 文件才能让 Yesod 考虑对其进行更新(我使用的是默认脚手架。也许这就是问题所在?)
TL;DR:我将 IO 相关变量插入到 Julius 中,但如果这些变量的内容发生变化,客户端将看不到更新的 JavaScript 文件,直到我手动更改 Julius 文件的时间戳。我希望在 IO 操作的内容发生更改时重新插入 JavaScript 文件。或者,我们可以假设它们在每次请求时都会发生变化(即是否有某种到期期限我可以设置为零?)
感谢您阅读这堵墙 o' 文字 :-)
所以看起来这实际上是 Yesod 中的一个错误,正如 Michael Snoyman 所指出的那样。我在 github 上打开了这个问题。