+1

[ExpressJS] Bài 10 - Viết Code Điều Hành Blog Cá Nhân (Tiếp Theo)

Trước khi bắt tay vào viết code xử lý chi tiết cho tuyến /article/add chúng ta hãy dành một chút thời gian để nhìn lại code tempate của giao diện soạn thảo bài viết mới đã xây dựng trong Sub-Series EJS.

<form id="article" action="<%= data.get("endpoint") %>" method="post">
   <div class="container">
      <input type="text" name="title" value="Bài Viết Mới" />
      
      <input type="text" name="keywords" placeholder="Từ khóa liên quan..." />
      
      <select name="category-id">
         <option> Danh Mục </option>
      <% for (var category of data.get("category-list")) { %>
         <option value="<%= category.get("@id") %>">
            <%= category.get("name") %>
         </option>
      <% } %>
      </select>

      <button type="submit"> Đăng bài </button>

      <textarea name="content" placeholder="Nội dung bài viết..."></textarea>
   </div><!-- .container -->
</form>

Như vậy là code điều hành của route này sẽ cần cung cấp cho template dữ liệu là danh sách đầy đủ các danh mục tại khóa category-list và đường dẫn tại khóa endpoint để trỏ tới router xử lý yêu cầu lưu bản ghi mới vào database.

Bổ sung router

Trước hết chúng ta cần khai báo thêm router mới tại index của nhóm route/article.

var express = require('express');
var router = express.Router();

router.use("/view", require("./action/view"));
router.use("/add", require("./action/add"));

module.exports = router;

Tổng quan xử lý route

router.get("/", async (request, response, next) => {
   var data = new Data();

   await getDataForTopnav(data);
   await getDataForArticle(data, "add");
   data.set("endpoint", "/article/add");

   response.render("index", {
      layout: "article",
      action: "add",
      data
   });
}); // router.get

Đường dẫn endpoint ở đây mình đặt là /article/add để trỏ lại chính xác router này. Và như vậy khi soạn thảo xong bài viết và nhấn nút "Đăng bài" thì chúng ta sẽ có một yêu cầu post được tiếp nhận như sau:

router.get("/", async (request, response, next) => {
   // --- yêu cầu xem giao diện soạn thảo bài viết mới
});

router.post("/", async (request, response, next) => {
   // --- yêu cầu lưu bài viết mới vào database
});

get-data-for-article

Trong code xử lý của sub-procedure truy vấn dữ liệu cho khu vực #article, chúng ta tiếp tục bổ sung logic rẽ nhánh cho action == "add".

module.exports = async (
   in_data = new Data(),
   in_action = "view",  /* view | add | edit */
   in_id = "Infinity"
) => {
   if (in_action == "view")
      await getArticle(in_data, in_id);
   else if (in_action == "add")
      await getCategoryList(in_data);
   else
      throw new Error("Unsupported action type");
};

/* getArticle... */

const getCategoryList = async (
   out_data = new Data()
) => {
   var categoryList = [];
   await databaseManager.execute(
      Category.name, "select",
      categoryList, Infinity, "default"
   );

   out_data.set("category-list", categoryList);
};

Chạy test kiểm tra

npm test

Server started

http://localhost:8080/article/add

Truy xuất dữ liệu gửi từ form

Để tách lấy dữ liệu gửi từ <form> nhập liệu về server ở dạng object, chúng ta có thể nhờ đến sự trợ giúp của hai middleware tiền xử lý do ExpressJS cung cấp mặc định là express.json()express.urlencoded(). Các middleware này cần được gắn trước các router xử lý form vì vậy nên chúng ta sẽ gắn luôn tại app.js để sử dụng chung cho tất cả các tuyến xử lý.

   /* --- Utility Middlewares */

app.use(logger("dev"));

app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.use(cookieParser());
app.use(express.static(pathToPublicFolder));

   /* --- Adding Routers... */

Và bây giờ chúng ta đã có thể truy xuất các cặp name/value do các <form> gửi về qua request.body.

   /* --- Receive Submitted */

router.post("/", async (request, response, next) => {
   console.log(request.body);
});

Và bây giờ chúng ta sẽ thử soạn thảo một bài viết mới rồi nhấn "Đăng bài" để xem thông tin nhận được trong request.body hiển thị trong console.

npm test

Server started

http://localhost:8080/article/add

Nhấn nút "Đăng bài":

Tổng quan xử lý yêu cầu post

Công việc mà chúng ta cần thực hiện ở đây là tạo ra một object mô tả bản ghi mới Article chưa có @id vì chưa được lưu vào database. Sau đó yêu cầu databaseManager ghi dữ liệu vào thư mục data. Nếu cần thiết bạn có thể lưu thêm thông tin về thời gian vào khóa edited-datetime của class Article. Ở đây mình sẽ chỉ lưu những thông tin vừa nhận được và không thêm thao tác truy vấn thời gian của hệ thống.

Sau khi đã thực hiện lưu trữ xong dữ liệu của bài viết mới, chúng ta sẽ có trị số @id đại diện cho bản ghi mới và có thể điều hướng tới trang hiển thị nội dung bài viết /article/view/:id bằng phương thức response.redirect(path).

/* router.get()... */

router.post("/", async (request, response, next) => {
   var entries = Object.entries(request.body);
   var submitted = new Article(entries);
   
   var inserted = new Article();
   await databaseManager.execute(
      Article.name, "insert",
      submitted, inserted
   );

   response.redirect(`/article/view/${inserted.get("@id")}`);
}); // router.post

module.exports = router;
npm start

Server started

Kết thúc bài viết

Như vậy là chúng ta đã thực hiện xong code xử lý yêu cầu cho tuyến /article/add bao gồm yêu cầu xem giao diện soạn thảo bài viết mới và yêu cầu lưu trữ bài viết mới vào database. Phương thức xử lý cho tuyến /article/edit/:id để chỉnh sửa nội dung của một bài viết cũng không có gì khác nhiều do đó chúng ta sẽ không thảo luận code chi tiết ở đây. Việc cần làm chỉ là truy vấn dữ liệu của bài viết đã có bằng tham số id và nạp vào <form> gửi cho trình duyệt web.

Tuyến article/delete/:id thì chỉ là một tính năng phụ của edit và có thể được bổ sung bằng một liên kết hoặc một nút nhấn trong <form> chỉnh sửa bài viết. Sau khi thực hiện xóa bài viết, bạn có thể chuyển hướng người dùng tới trang chủ hoặc trang đơn danh mục.

Trong những bài viết tiếp theo, chúng ta sẽ xây dựng nốt giao diện đăng nhập và quản trị đơn giản.

[EJS] Bài 9 - Viết Code Xây Dựng Giao Diện Blog (Kết Thúc)

Sau đó viết code điều hành để bổ sung tính năng bảo mật đơn giản này cho blog và đăng tải lên Glitch.com.

[ExpressJS] Bài 11 - Viết Code Điều Hành Blog Cá Nhân (Tiếp Theo)


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.