图书列表页面
接下来,我们将实现我们的图书列表页面。此页面需要显示数据库中所有图书的列表,以及它们的作者,每个图书标题都是指向其关联的图书详情页面的超链接。
控制器
图书列表控制器函数需要获取数据库中所有Book
对象列表,对其进行排序,然后将这些对象传递给模板进行渲染。
打开/controllers/bookController.js。找到导出的book_list()
控制器方法,并将其替换为以下代码。
// Display list of all books.
exports.book_list = asyncHandler(async (req, res, next) => {
const allBooks = await Book.find({}, "title author")
.sort({ title: 1 })
.populate("author")
.exec();
res.render("book_list", { title: "Book List", book_list: allBooks });
});
路由处理程序在Book
模型上调用find()
函数,选择仅返回title
和author
,因为我们不需要其他字段(它还会返回_id
和虚拟字段),并使用sort()
方法按标题字母顺序对结果进行排序。我们还在Book
上调用populate()
,指定author
字段——这将用完整的作者详细信息替换存储的图书作者 ID。然后,exec()
在末尾链接,以执行查询并返回一个 Promise。
路由处理程序使用await
等待 Promise,暂停执行直到 Promise 完成。如果 Promise 已完成,则查询结果将保存到allBooks
变量中,处理程序继续执行。
路由处理程序的最后一部分调用render()
,指定book_list(.pug)模板并将title
和book_list
的值传递到模板中。
视图
创建/views/book_list.pug并将下面的文本复制到其中。
extends layout
block content
h1= title
if book_list.length
ul
each book in book_list
li
a(href=book.url) #{book.title}
| (#{book.author.name})
else
p There are no books.
该视图扩展了layout.pug基本模板并覆盖了名为'content'的block
。它显示我们从控制器(通过render()
方法)传入的title
,并使用each
-in
语法遍历book_list
变量。为每本书创建一个列表项,显示图书标题作为指向图书详情页面的链接,后跟作者姓名。如果book_list
中没有图书,则执行else
子句,并显示文本“没有图书”。
注意:我们使用book.url
为每本书提供指向详细信息记录的链接(我们已经实现了此路由,但尚未实现页面)。这是Book
模型的一个虚拟属性,它使用模型实例的_id
字段生成唯一的 URL 路径。
这里值得注意的是,每本书被定义为两行,使用管道符作为第二行。需要这种方法是因为如果作者姓名在上一行,那么它将成为超链接的一部分。
它是什么样子的?
运行应用程序(有关相关命令,请参阅测试路由),并在浏览器中打开https://127.0.0.1:3000/
。然后选择“所有图书”链接。如果一切设置正确,您的网站应该如下面的屏幕截图所示。
后续步骤
- 返回Express 教程第 5 部分:显示库数据。
- 继续第 5 部分的下一个子文章:BookInstance 列表页面。