【Node.js】Expressで、JSONデータを編集する方法
Node.js

【Node.js】Expressで、JSONデータを編集する方法

作成日:2021年10月28日
更新日:2021年10月29日

前回は、Express で、JSON データを削除する方法を紹介しました。

nodejs-mvc-delete

【Node.js】Expressで、JSONデータを削除する方法

今回は、JSON データを編集する方法を紹介します。

コードは、前回のコードを使用します。

views/index.ejs

ejs
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%= pageTitle %></title>
</head>
<body>
<main>
<h1>メニュー</h1>
<p>メニュー一覧</p>
<% if(menus.length > 0) { for (let menu of menus){ %>
<p><%= menu.title %></p>
<div>
<form action="/delete-menu" method="POST">
<input type="hidden" value="<%= menu.id %>" name="menuId" />
<button type="submit">削除</button>
</form>
</div>
<%} %> <% } else { %>
<p>注文がありません</p>
<% } %>
</main>
</body>
</html>

views/menu.ejs

ejs
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/css/styles.css" />
<title><%= pageTitle %></title>
</head>
<body>
<main>
<form action="/menu" method="POST">
<div class="form-control">
<label for="title">メニュー名</label>
<input type="text" name="title" />
</div>
<div class="form-control">
<label for="description">内容</label>
<input type="text" name="description" />
</div>
<button type="submit">メニューを追加する</button>
</form>
</main>
</body>
</html>

views/menu-detail.ejs

ejs
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%= pageTitle %></title>
</head>
<body>
<main>
<h1><%= menu.title %></h1>
<p><%= menu.description %></p>
</main>
</body>
</html>

index.js

js
const express = require("express");
const app = express();
const path = require("path");
app.set("view engine", "ejs");
app.set("views", "views");
const menuRoutes = require("./routes/index.js");
const menus = require("./routes/menu.js");
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, "public")));
app.use("/", menus);
app.use(menuRoutes);
app.use((req, res, next) => {
res.status(404).send("<h1>ページが見つかりません</h1>");
});
app.listen(8000, () => console.log("Server is running ..."));

models/menu.js

js
const fs = require("fs");
const path = require("path");
const menus = [];
module.exports = class Menu {
constructor(id, title, description) {
this.id = id;
this.title = title;
this.description = description;
}
save() {
this.id = (Math.random() + 1).toString(36).slice(2, 8);
const menuPath = path.join(
path.dirname(require.main.filename),
"data",
"menus.json"
);
fs.readFile(menuPath, (err, fileContent) => {
let menus = [];
if (!err) {
menus = JSON.parse(fileContent);
}
menus.push(this);
fs.writeFile(menuPath, JSON.stringify(menus), (err) => {
console.log(err);
});
});
}
static fetchAll(data) {
const menuPath = path.join(
path.dirname(require.main.filename),
"data",
"menus.json"
);
fs.readFile(menuPath, (err, fileContent) => {
if (err) {
data([]);
}
data(JSON.parse(fileContent));
});
}
static fetchMenu(id, data) {
const menuPath = path.join(
path.dirname(require.main.filename),
"data",
"menus.json"
);
fs.readFile(menuPath, (err, fileContent) => {
if (err) {
data([]);
}
const menuData = JSON.parse(fileContent);
const menuDetail = menuData.find((menu) => menu.id === id);
data(menuDetail);
});
}
};

controllers/menus.js

js
const Menu = require("../models/menu");
exports.getAddMenu = (req, res, next) => {
res.render("menu", { pageTitle: "メニュー追加" });
};
exports.postAddMenu = (req, res, next) => {
const id = req.body.id;
const title = req.body.title;
const description = req.body.description;
const menu = new Menu(id, title, description);
menu.save();
res.redirect("/");
};
exports.getAddMenus = (req, res, next) => {
Menu.fetchAll((menus) => {
res.render("index", {
pageTitle: "メニュー一覧",
menus,
});
});
};
exports.getMenu = (req, res, next) => {
const id = req.params.menuId;
Menu.fetchMenu(id, (menu) => {
res.render("menu-detail", {
menu: menu,
pageTitle: "詳細画面",
});
});
};
exports.postDeleteMenu = (req, res, next) => {
const id = req.body.menuId;
Menu.deleteMenu(id);
res.redirect("/");
};

routes/index.js

js
const express = require("express");
const router = express.Router();
const menuController = require("../controllers/menus");
router.get("/", menuController.getAddMenus);
module.exports = router;

routes/menu.js

js
const express = require("express");
const router = express.Router();
const menuController = require("../controllers/menus");
router.get("/menu", menuController.getAddMenu);
router.get("/menu/:menuId", menuController.getMenu);
router.post("/menu", menuController.postAddMenu);
router.post("/delete-menu", menuController.postDeleteMenu);
module.exports = router;

編集ページを作成

作成したデータを編集するページを作成します。

ページは、menu.ejs をコピーします。

views/menu-edit.ejs

ejs
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/css/styles.css" />
<title><%= pageTitle %></title>
</head>
<body>
<main>
<form action="/edit-menu" method="POST">
<div class="form-control">
<label for="title">メニュー名</label>
<input type="text" name="title" />
</div>
<div class="form-control">
<label for="description">内容</label>
<input type="text" name="description" />
</div>
<button type="submit">メニューを更新する</button>
</form>
</main>
</body>
</html>

このままでは、メニューの内容が表示されないので、inputの中にvalueを設定します。

ejs
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/css/styles.css" />
<title><%= pageTitle %></title>
</head>
<body>
<main>
<form action="/edit-menu" method="POST">
<div class="form-control">
<label for="title">メニュー名</label>
<input type="text" name="title" value="<%= menu.title %>" />
</div>
<div class="form-control">
<label for="description">内容</label>
<input
type="text"
name="description"
value="<%= menu.description %>"
/>
</div>
<button type="submit">メニューを更新する</button>
</form>
</main>
</body>
</html>

メニューの ID も必要なので、inputtype="hidden"にして、ID を指定します。

ejs
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/css/styles.css" />
<title><%= pageTitle %></title>
</head>
<body>
<main>
<form action="/edit-menu" method="POST">
<input type="hidden" name="id" value="<%= menu.id %>" />
<div class="form-control">
<label for="title">メニュー名</label>
<input type="text" name="title" value="<%= menu.title %>" />
</div>
<div class="form-control">
<label for="description">内容</label>
<input
type="text"
name="description"
value="<%= menu.description %>"
/>
</div>
<button type="submit">メニューを更新する</button>
</form>
</main>
</body>
</html>

views フォルダの index.ejs に編集画面へ遷移するリンクを作成しましょう。

ejs
<div>
<a href="/edit-menu/<%= menu.id %>">編集</a>
<form action="/delete-menu" method="POST">
<input type="hidden" value="<%= menu.id %>" name="menuId" />
<button type="submit">削除</button>
</form>
</div>

編集画面にデータを表示する

ホーム画面の編集ボタンをクリックすると、編集画面に遷移するようにします。

models フォルダの menus.js にgetEditMenuを作成します。

getEditMenuの内容は、getMenuをコピーします。

js
exports.getEditMenu = (req, res, next) => {
const id = req.params.menuId;
Menu.fetchMenu(id, (menu) => {
res.render("menu-detail", {
menu: menu,
pageTitle: "詳細画面",
});
});
};

遷移先をmenu-detailからmenu-editへ変更します。

また、pageTitle も変更しておきましょう。

js
exports.getEditMenu = (req, res, next) => {
const id = req.params.menuId;
Menu.fetchMenu(id, (menu) => {
res.render("menu-edit", {
menu: menu,
pageTitle: "メニュー内容編集",
});
});
};

routes フォルダの menu.js に、getを使って、コントローラーを設定します。

js
router.get("/edit-menu/:menuId", menuController.getEditMenu);

これで、コントローラーは完成です。

一度ブラウザで確認してみます。

image2

『編集』をクリックします。

image3

フォーム内に選択したデータが表示されました。

メニューを更新する

それでは、メニューを更新する処理を作成します。

models フォルダの menu.js を開きます。

『メニューを更新する』ボタンをクリックした後、モデルのsave内で処理します。

今、save内では、新規作成の場合にデータが保存されるようになっています。

更新の場合に処理するために、ifで条件分けします。

条件は、this.idが存在する場合にします。

js
save() {
if (this.id) {
} else {
this.id = (Math.random() + 1).toString(36).slice(2, 8);
const menuPath = path.join(
path.dirname(require.main.filename),
"data",
"menus.json"
);
fs.readFile(menuPath, (err, fileContent) => {
let menus = [];
if (!err) {
menus = JSON.parse(fileContent);
}
menus.push(this);
fs.writeFile(menuPath, JSON.stringify(menus), (err) => {
console.log(err);
});
});
}
}

JSON の URL を作成します。

js
if (this.id) {
const menuPath = path.join(
path.dirname(require.main.filename),
"data",
"menus.json"
);
} else {

JSON.parseで JSON データを読み込みましょう。

js
if (this.id) {
const menuPath = path.join(
path.dirname(require.main.filename),
"data",
"menus.json"
);
fs.readFile(menuPath, (err, fileContent) => {
const menuData = JSON.parse(fileContent);
});
} else {

findIndexを使用して、JSON 内の ID と更新したいデータの ID が一致しているデータを指定します。

js
fs.readFile(menuPath, (err, fileContent) => {
const menuData = JSON.parse(fileContent);
const thisMenu = menuData.findIndex((menu) => menu.id === this.id);
});

すべてのメニュー内容を指定して、その中からthisMenuに当たるデータを書き換えます。

js
const menuPath = path.join(
path.dirname(require.main.filename),
"data",
"menus.json"
);
fs.readFile(menuPath, (err, fileContent) => {
const menuData = JSON.parse(fileContent);
const thisMenu = menuData.findIndex((menu) => menu.id === this.id);
const menuUpdate = [...menuData];
menuUpdate[thisMenu] = this;
});

書き換えたデータを JSON ヘ保存します。

js
const menuPath = path.join(
path.dirname(require.main.filename),
"data",
"menus.json"
);
fs.readFile(menuPath, (err, fileContent) => {
const menuData = JSON.parse(fileContent);
const thisMenu = menuData.findIndex((menu) => menu.id === this.id);
const menuUpdate = [...menuData];
menuUpdate[thisMenu] = this;
fs.writeFile(menuPath, JSON.stringify(menuUpdate), (err) => {
console.log(err);
});
});

controllers フォルダの menus.js に更新したいデータを指定します。

js
exports.postEditMenu = (req, res, next) => {
const id = req.body.id;
const updatedTitle = req.body.title;
const updatedDescription = req.body.description;
};

モデルと接続しましょう。

js
exports.postEditMenu = (req, res, next) => {
const id = req.body.id;
const updatedTitle = req.body.title;
const updatedDescription = req.body.description;
const updatedMenu = new Menu(id, updatedTitle, updatedDescription);
updatedMenu.save();
};

ホーム画面へリダイレクトします。

js
exports.postEditMenu = (req, res, next) => {
const id = req.body.id;
const updatedTitle = req.body.title;
const updatedDescription = req.body.description;
const updatedMenu = new Menu(id, updatedTitle, updatedDescription);
updatedMenu.save();
res.redirect("/");
};

routes フォルダの menu.js に、postを使って、コントローラーを設定します。

js
router.post("/edit-menu", menuController.postEditMenu);

これで完成しましたので、確認してみます。

image4

image5

『味噌かつ定食』を編集します。

image6

image7

image8

『味噌かつ定食』のメニュー名を更新することができました。

© 2024あずきぱんウェブスタジオ