テキストを変更できるリストを作る JavaScript初学者講座

JavaScript

前回の記事ではul要素内にli要素を追加・削除できるプログラムを作りました。ただ単にli要素が増えて行っても実用性がないので、li要素のテキストを変更できるようにカスタマイズしていきます。

HTMLは編集と編集完了時の決定ボタンを追加し、決定ボタンはCSSでいったん非表示にしておきます。その他JavaScriptで操作する時のために構造を少し変更します。

<style>
  .list__item {
    display: flex;
    align-items: center;
  }

  .list__item + .list__item {
    border-top: 1px solid #ccc;
    margin-top: 16px;
    padding-top: 16px;
  }

  .list__itemButtons {
    display: flex;
    align-items: center;
    margin-left: 24px;
  }

  .button {
    margin-left: 20px;
  }

<ul class="list">
  <li class="list__item">
    <div class="list__itemBody">テスト</div>
    <div class="list__itemButtons">
      <div class="button button--delete">削除</div>
      <div class="button button--edit">編集</div>
      <div class="button button--submit hidden">決定</div>
    </div>
  </li>
</ul>
<button class="button button--add">追加</button>

次にJavaScriptのコードを変更します。今回はまず完成したサンプルとコードを見ていただき、説明していきたいと思います。

<script>
  // HTMLを変数に代入
  const list = document.querySelector(".list");
  const listItem = list.children;
  const listItemBody = ".list__itemBody";
  const deleteButton = ".button--delete";
  const editButton = ".button--edit";
  const submitButton = ".button--submit"
  
  // ページ読み込み時点で表示されているli要素にボタンの機能を関連づける
  for( let i = 0; i < listItem.length; i++) {

    // li内の要素を変数に代入
    const itemBody = listItem[i].querySelector(listItemBody);
    const itemDeleteButton = listItem[i].querySelector(deleteButton);
    const itemEditButton = listItem[i].querySelector(editButton);
    const itemSubmitButton = listItem[i].querySelector(submitButton);

    // 削除ボタン
    itemDeleteButton.addEventListener("click", () => {
      
      listItem[i].remove();

    });

    // 編集ボタン
    itemEditButton.addEventListener("click", () => {

      const inputForm = document.createElement("input");
      inputForm.type = "text";
      inputForm.className = "inputText";
      inputForm.value = itemBody.textContent;

      itemBody.replaceChildren(inputForm);
      
      itemDeleteButton.classList.add("hidden");
      itemEditButton.classList.add("hidden");
      itemSubmitButton.classList.remove("hidden");

    });

    // 編集後の決定ボタン
    itemSubmitButton.addEventListener("click", () => {
      const inputForm = listItem[i].querySelector(".inputText");
      itemBody.replaceChildren(inputForm.value);

      itemDeleteButton.classList.remove("hidden");
      itemEditButton.classList.remove("hidden");
      itemSubmitButton.classList.add("hidden");
    });

  }
  
  // 追加ボタン
  const addButton = document.querySelector(".button--add");
  
  addButton.addEventListener("click", () => {

    // 追加時のli要素を作成
    const listItemElement = document.createElement("li");
    listItemElement.className = "list__item";
    listItemElement.innerHTML = `
    <div class="list__itemBody">テスト</div>
    <div class="list__itemButtons">
      <div class="button button--delete">削除</div>
      <div class="button button--edit">編集</div>
      <div class="button button--submit hidden">決定</div>
      </div>
    `;
    
    // 追加したli内の要素を変数に代入
    const itemDeleteButton = listItemElement.querySelector(deleteButton);
    const itemEditButton = listItemElement.querySelector(editButton);
    const itemSubmitButton = listItemElement.querySelector(submitButton);
    const itemBody = listItemElement.querySelector(listItemBody);

    // 削除ボタン
    itemDeleteButton.addEventListener("click", () => {
      listItemElement.remove();
    })

    // 編集ボタン
    itemEditButton.addEventListener("click", () => {

      const inputForm = document.createElement("input");
      inputForm.type = "text";
      inputForm.className = "inputText";
      inputForm.value = itemBody.textContent;

      itemBody.replaceChildren(inputForm);
      
      itemDeleteButton.classList.add("hidden");
      itemEditButton.classList.add("hidden");
      itemSubmitButton.classList.remove("hidden");

    });

    // 編集後の決定ボタン
    itemSubmitButton.addEventListener("click", () => {
      const inputForm = listItemElement.querySelector(".inputText");
      itemBody.replaceChildren(inputForm.value);

      itemDeleteButton.classList.remove("hidden");
      itemEditButton.classList.remove("hidden");
      itemSubmitButton.classList.add("hidden");
    });

    list.appendChild(listItemElement);
  });

</script>

コードの実行サンプル

編集ボタンの追加

まずは編集ボタンの機能を実装を見ていきましょう。

 const inputForm = document.createElement("input");
 inputForm.type = "text";
 inputForm.className = "inputText";
 inputForm.value = itemBody.textContent;

変数 inputForm にテキスト入力ができる <input type=”text”> を作っていきます。処理の流れは下記の通りになっています。

  1. input要素を変数に代入
  2. input要素のtypeにtextを設定
  3. input要素のclassにinputTextを設定
  4. input要素のvalueの値に現在リストに表示されているテキストを設定

最後にinuptのvalueへもとのテキストを入れることで、編集状態に現在のテキストを引き継いでいます。

  itemBody.replaceChildren(inputForm);

replaceChildren は指定された要素を子要素を全て置き換えるメソッドです。
サンプルのコードだと .list__itemBody 内のテキストがinputの要素に置き換わるようになっています。

itemDeleteButton.classList.remove("hidden");
itemEditButton.classList.remove("hidden");
itemSubmitButton.classList.add("hidden");

最後はli要素内のボタンの表示・非表示を切り替えています。classList プロパティに.remove や .add のメソッドを使うことで、classの追加・削除をしています。
ここではclassの「hidden」を追加・削除することでボタンの表示を切り替えています。

編集後の決定ボタン

編集でテキストの変更を行い、決定ボタンを押すとその内容が反映されて元のボタンへ戻るようにします。今まで勉強してきたことだけで出来ているの説明の必要はないかもしれませんが、わかる方は答え合わせのつもりで見ていきましょう。

const inputForm = listItemElement.querySelector(".inputText");
itemBody.replaceChildren(inputForm.value);

itemDeleteButton.classList.remove("hidden");
itemEditButton.classList.remove("hidden");
itemSubmitButton.classList.add("hidden");

処理の流れを下記にまとめます。

  1. input要素を変数に代入
  2. input要素valueの値を変数itemBodyの子要素と置き換え
  3. ボタンのclass「hidden」の追加・削除で、表示・非表示の切り替え

どの処理もこれまでやってきたことの応用ですね。これで編集ボタンのプログラムが完成しました。

追加したli要素の編集ボタンを実装

次は追加ボタンによって増えたli要素の編集ボタンの関連づけをしていきましょう。プログラムの内容はあまり変わらないので細かくは説明しませんが、似たようなコードが2回書かれていることをみると改善の余地があります。

同じ処理であれば関数を定義して使ったほうが、同じ記述を2度以上しなくて済みます。一度作ったコードを見直してブラッシュアップし、さらに良いコードへ書き換えることをリファクタリングと呼びます。こちらについてはいずれ他の記事でやっていきたいと思います。

終わりに

編集ボタンを追加したのことで、だいぶインタラクティブなやりとりが可能なページになってきました。こういったプログラムは多機能なフォームを作るときに重宝されるんじゃないかと思います。単純なコードではありますが、HTMLをJavaScriptで操作することに慣れるための練習として学習していきましょう。

ここまで読んでくださり、ありがとうございました。

本記事で記述したコード
otoiron/web-dukuri-study | GitHub

制作協力
サムネイル制作:うみ Twitter

コメント

タイトルとURLをコピーしました