Expressで作るアプリ開発入門 更新実装編

Express

前回の内容

前回は、商品追加ページの実装をしました↓
https://sakublog.tech/handson/express-app-3/

今回は商品を更新できるようにします。

一覧から更新ページに遷移させる

index.ejsに、各商品にリンクを設置します。

aタグのhrefを書き換えます。

      <ul class="products">
        <% drinks.forEach((drink)=>{ %>
        <li class="product">
          <h2 class="product-name">
            <a class="product-link" href="/update?id=<%= drink.id %>"
              ><%= drink.name %></a
            >
          </h2>
          <p class="product-price">¥<%= drink.price %></p>
          <p
            class="product-temperature <%= drink.temperature ? 'warm' :'cold' %>"
          >
            <%= drink.temperature ? "あたたかい" :"つめたい" %>
          </p>
          <button>購入</button>
        </li>
        <% }) %>
      </ul>

これで、クエリパラメータに飲み物のidをつけることができました。

初期値を表示

次に、編集する内容の初期値をフォームに入れます。

  • クエリパラメータのidをもとに商品情報を取得
  • 商品情報をフォームに渡す

このようなステップで処理を書いていきます。

クエリパラメータのidをもとに商品情報を取得

クエリパラメータは req.query で受け取ることができます

idを受け取れるようにしましょう。

app.get("/update", (req, res) => {
  const id = req.query.id;
  console.log(id);
  res.render("update");
});
http://localhost:3000/update?id=2

にアクセスしてコンソールを見てみます。

idが取得できればOKです🙌

今度はこのidに合致する商品情報を取得しましょう!

app.get("/update", async (req, res) => {
  const connection = await mysql.createConnection({
    host: process.env.MYSQL_HOST,
    database: process.env.MYSQL_DATABASE,
    user: process.env.MYSQL_USER,
    password: process.env.MYSQL_PASSWORD,
  });
  const id = req.query.id;
  const sql = "SELECT * FROM drinks WHERE id = ?";
  const result = await connection.execute(sql, [id]);
  console.log(result);
  await connection.end();
  res.render("update");
});

データベースに接続し、select文で該当idの結果を取得しています。

これで

http://localhost:3000/update?id=2

にアクセスします。

id=2の商品が取得できたらOKです!

商品情報をフォームに渡す

SQLで商品を取得できたら、Expressからejsにデータを渡します。

これは一覧ページと同じ要領でできます。

renderメソッドの第二引数に入れてあげれば良いです。

  res.render("update", { drink: result[0][0] });

これでupdate.ejs側に「drink」という変数で結果が渡ってきます。

formを編集します。

      <form action="#" method="POST">
        <label for="drink-name">商品名:</label>
        <input
          type="text"
          id="drink-name"
          name="name"
          required
          value="<%= drink.name %>"
        />

        <label for="drink-price">価格:</label>
        <input
          type="number"
          id="drink-price"
          name="price"
          required
          value="<%= drink.price %>"
        />

        <label for="drink-temp">温度:</label>
        <select id="drink-temp" name="temp">
          <option <%= drink.temperature === 1 ? 'selected' : '' %> value="1">あたたかい</option>
          <option <%= drink.temperature === 0 ? 'selected' : '' %> value="0">冷たい</option>
        </select>

        <button type="submit">更新する</button>
      </form>

value属性に初期値を入れると表示されます。

selectタグは、drink.temperatureが1か0かでselected属性を付与しています。

これでフォームに初期値が入るようになりました!

また、更新にはどの商品かが判る必要があるので、idも送信します。

input type=”hidden”

でidを送れるようにしましょう。

 <input type="hidden" name="id" value="<%= drink.id %>">

上記をフォームの中に設定すれば準備OKです。

フォームからの値を受け取りバリデーション

追加ページと同様、フォームからのデータをExpress側で受け取れるようにします。

update.ejsのactionを編集します。

<form action="/update" method="POST">

追加と同様に、req.bodyで受け取ることができます。

app.jsにpost時の処理を追加します。


app.post("/update", (req, res) => {
  const errors = {
    name: [],
    price: [],
    temp: [],
  };
  if (req.body.name.length > MAX_NAME_LENGTH) {
    errors.name.push("商品名は20文字以内です。");
  }
  if (req.body.price >= MAX_PRICE || req.body.price <= MIN_PRICE) {
    errors.price.push("価格は999円以内で設定できます。");
  }
  if (req.body.temp !== TEMP_WARM && req.body.temp !== TEMP_COLD) {
    errors.temp.push("温度の選択肢が不正です。");
  }
  if (errors.name.length || errors.price.length || errors.temp.length) {
    return res.render("add", { errors: errors });
  }
  res.redirect("/");
});

追加処理のバリデーション内容をそのままコピーしてきました。

idのバリデーションも追加します。

app.post("/update", (req, res) => {
  const errors = {
    id: [], // 追記
    name: [],
    price: [],
    temp: [],
  };
  if (!req.body.id) {
    errors.name.push("商品idは必須です。"); // 追記
  }
  if (req.body.name.length > MAX_NAME_LENGTH) {
    errors.name.push("商品名は20文字以内です。");
  }
  if (req.body.price >= MAX_PRICE || req.body.price <= MIN_PRICE) {
    errors.price.push("価格は999円以内で設定できます。");
  }
  if (req.body.temp !== TEMP_WARM && req.body.temp !== TEMP_COLD) {
    errors.temp.push("温度の選択肢が不正です。");
  }
  if (errors.name.length || errors.price.length || errors.temp.length) {
    return res.render("add", { errors: errors });
  }
  res.redirect("/");
});

追記できたらバリデーションは完成です。

更新処理

SQLのUPDATE文で更新します。

  if (errors.name.length || errors.price.length || errors.temp.length) {
    return res.render("add", { errors: errors });
  }
  const connection = await mysql.createConnection({
    host: process.env.MYSQL_HOST,
    database: process.env.MYSQL_DATABASE,
    user: process.env.MYSQL_USER,
    password: process.env.MYSQL_PASSWORD,
  });
  const sql = `UPDATE drinks SET name=?,price=?,temperature=? WHERE id = ?`;
  await connection.query(sql, [
    req.body.name,
    req.body.price,
    req.body.temp,
    req.body.id,
  ]);
  await connection.end();
  res.redirect("/");

INSERTとほとんど同じです。

この状態で画面から更新できるか確かめてみましょう。

id=1のコーヒーを変更してみます。

詳細に遷移し、

次のように変更してみます。

これで更新すると、

更新できました!!!

これで更新処理は完成です。

ここまでお疲れ様でした🙌

次回は削除処理を実装します。