将后端数据注入视图以在客户端 JS 中使用

Injecting backend data into view for use in client-side JS

我想 return 将文档列表添加到数组中,该数组将在某些客户端 JS 中使用。在我的 apsotrophe-pages 模块中,我有这个正在工作的 apos.docs.find 调用和我需要获取的 returning 文档。现在我有了这个文档数组,我需要将数据公开给客户端 JS。

通读文档,看起来可能建议使用 pieces 来执行此操作,但看起来这些 pieces 需要放入小部件中,然后再将小部件放入页面中。

我理解模块分离的最佳实践,但我只是希望尽可能简单和轻松地获取这些数据以供客户端使用(有点时间紧迫)。

有没有一种简单易行的方法可以让我将这个 autoCompleteData 数组暴露给前端,这样我就可以在我的客户端代码中做类似下面的事情?

(感谢您的帮助!过去几天我遇到了几个撇号问题,但我认为这是帮助我填补后端对象与前端连接空白的最后一部分。)

\lib\modules\apostrophe-pages\views\pages\home.html

 <script>
   var page = apos.page;
   $('#displayDocs').text(page.autoCompleteData);
 </script>

\lib\modules\apostrophe-pages\index.js

 module.exports = {
  types: [
     { name: 'default', label: 'Default Page' },
     { name: 'apostrophe-blog-page', label: 'Blog Index' },
  ],
  autoCompleteData: [],
  construct: function(self, options) {

    self.pageBeforeSend = function(req, callback) {

       let criteria = [
         {"type": "apostrophe-blog"}, 
         {"published": true}
       ];
       criteria = { $and: criteria };

       self.apos.docs.find(req, criteria).sort({ title: 1 }).toObject(function(err, collection){     
       self.autoCompleteData = collection;
    });

    return callback(null);
  }
 }
}

如你所知,我在 P'unk Avenue 领导 Apostrophe 团队。

您即将解决您的问题。您只需将返回的数据附加到 req.data,这样它就可以在 Nunjucks 模板中作为 data 对象的一部分显示。

但是你也需要更加小心你的异步编程。现在你正在发出一个异步请求去获取一些文档;与此同时,您正在立即调用您的回调。这是不对的 — 回调的要点是,在您实际拥有数据并准备好在模板中呈现它之前,您不会调用它。

这里是对相关代码的更正:

self.apos.docs.find(req, criteria).sort(
  { title: 1 }
).toArray(function(err, autocomplete) {
  if (err) {
    return callback(err);
  }
  req.data.autocomplete = autocomplete;   
  return callback(null);
});  

我所做的更改:

  • 我叫toArray,不是toObject。您对此处不止一件物品感兴趣。
  • 我在继续之前检查错误。如果有,我将其传递给回调和 return.
  • 我将数组分配给 req.data.autocomplete,以便我的 nunjucks 页面模板和它们扩展的布局可以看到它。
  • 之后我用 null 调用回调以指示成功,然后 return.

请注意,我在调用回调时总是使用 return 关键字。永远回归 (ABR)。否则,您的代码将继续以您不希望的方式执行。

这段代码会有一些性能问题,因为如果片段有区域和连接等等,它会获取大量信息。您应该考虑添加投影:

self.apos.docs.find(req, criteria, { title: 1, slug: 1 })...

将您为此目的关心的任何其他属性添加到投影中的属性。 (这是一个标准的 MongoDB 投影,如果您想了解更多信息,请阅读这些内容。)

使用"super pattern"保持原来的pageBeforeSend方法

apostrophe-pages 模块已经有一个 pageBeforeSend 方法,它做了重要的工作。如果您只是覆盖它,您将失去这项工作的好处。

一个解决方案是在您的项目中创建一个新模块,一个根本不扩展另一个模块,并在其中引入一个 pageBeforeSend 方法。由于 pageBeforeSend 是由 Apostrophe 的 callAll 机制调用的,因此它会为每个具有一个的模块调用。

另一个解决方案是遵循 "super pattern" 以确保方法的原始版本也被调用:

var superPageBeforeSend = self.pageBeforeSend;
self.pageBeforeSend = function(req, callback) {
  // Do our things here, then...
  return superPageBeforeSend(req, callback);
};

在浏览器中将数据传递给 javascript

回答你的下一个问题 (:

在您的页面模板中,您现在可以写:

<script>
  var autocomplete = {{ data.autocomplete | json }};
</script>

json nunjucks 过滤器将数组转换为 JSON,保证可以安全地输出到这样的脚本标记中。所以你在浏览器端得到了一个很好的数组 JavaScript.

对适当的内容类型使用 find 方法

您可以避免为了获得正确类型的内容和检查已发布的内容等而创建自己的条件对象的麻烦。而是考虑编写:

self.apos.modules['apostrophe-blog'].find(req, {}).sort()...

每个 pieces 模块都有自己的 find 方法,该方法 return 是针对该类型定制的游标,因此它将更好地坚持已达到发布日期的内容和其他内容你可能没有想到。

希望对您有所帮助!