現在、もりけん塾にてJavaScriptを勉強させていただいております。その記録。
今回は課題20についての備忘録です。

考え方が間違っている箇所もあるかと思いますが、お気づきの際はご指摘いただければと思います。

課題20について

仕様

  • こちらのようなテーブルを画面遷移してから3秒後に解決されるPromiseが返すオブジェクトを元に作ってください。
  • カラム名など(id, 名前等)もdataで表現して受け取り、フロント側で加工して表示すること
  • APIデータのidはリアルではない採番や、別idを付与しても良い
  • その時、idは要素の並び順でつけず以下のように順不同にしてください

制作物

コードはこちらから(codesandbox)

※codesandboxではエラーが出る場合がありますが、リロードすれば動きます。

実装内容

JSONデータの作成

まずはJSONデータを作成。下記のようにしました。

JASONデータ

{
  "data": [
    {
      "id": "83c2ec33-b6cd-4ac3-b5b3-41e14ab8d2f8",
      "userId": 1,
      "name": "やまだ",
      "gender": "男",
      "age": 32
    },
    {
      "id": "c61573c5-b5bc-4f0d-a06c-11617e6f8ccc",
      "userId": 2,
      "name": "さとう",
      "gender": "女",
      "age": 18
    },
    {
      "id": "a3566086-a482-4b76-8070-1c2f51b52a9e",
      "userId": 3,
      "name": "たなか",
      "gender": "男",
      "age": "25"
    },
    {
      "id": "5eee53e8-314c-4bb1-bbc1-3eace56eaf1b",
      "userId": 4,
      "name": "あんどう",
      "gender": "女",
      "age": 48
    },
    {
      "id": "10bda69f-709b-4129-acf0-d3ccbdb000a7",
      "userId": 5,
      "name": "えのもと",
      "gender": "女",
      "age": 36
    }
  ]
}

Table要素の組み立て

JASONデータを加工するために、userDataColumnというオブジェクトを作成しました。それを使用してテーブルの組み立てを行いました。

渡ってきたJSONデータをrenderTableElement()へ渡す。
①table,tbody要素を作成する。
②userDataColumnオブジェクトのvalue値を取得して、テーブルのヘッダー部組み立てのための関数に渡す。
③tbody配下の要素を作成する関数へ渡ってきたユーザーデータを渡す。

const userDataColumn = {
  userId: "ID",
  name: "名前",
  gender: "性別",
  age: "年齢"
}

const renderTabaleElement = (userData)  => {
  const table = createElementWithClassName("table", "table");
  const tbody = createElementWithClassName("tbody", "tbody");
  const tableHeadValue = Object.values(userDataColumn);
  wrapper.appendChild(table).appendChild(getTableHeadElement(tableHeadValue));
  wrapper.appendChild(table).appendChild(tbody).appendChild(getTableRowFragment(userData));
}

レビューPOINT

userDataColumnオブジェクトの名前を当初、userDataItemを使用していましたが、Columnの方が一般的とのご指摘を受け変更しました。

テーブルヘッダー組み立て関数

ここでは渡ってきたuserDataColumnオブジェクトのValue値をそのまま使用してテーブルヘッダー部を組み立てます。

const getTableHeadElement = (tableHeadValue) => {
  const thead = createElementWithClassName("thead", "thead");
  const tr = createElementWithClassName("tr", "tr");
  const fragmentThElement = document.createDocumentFragment();
  for (const value of tableHeadValue) {
    const th = createElementWithClassName("th", "th");
    th.textContent = value;
    fragmentThElement.appendChild(tr).appendChild(th);
  }
  thead.appendChild(fragmentThElement);

  return thead;
}

//当初のコード
// const getTableHeadElement = (tableHeadValue) => {
//   const tr = createElementWithClassName("tr", "tr");
//   const fragmentThElement = document.createDocumentFragment();
//   for (const value of tableHeadValue) {
//     const th = createElementWithClassName("th", "th");
//     th.textContent = value;
//     fragmentThElement.appendChild(tr).appendChild(th);
//   }
//   return fragmentThElement;
// }

レビューPOINT

当初のPR時では、関数名でElementを使用していながら、fragmentを返す関数にしていました。
内容と名前がずれているので、関数名を変えるか名前の通りにTh要素を返す関数に内容を変えてはどうかとレビューいただきました。

言われてみればその通りだと、安易な命名をしてしまったと反省。
中身をtheadを返す関数へ変更しました。また、当初theadを使用せず、tbodyに入れていたので、そこもここの箇所にてtheadに入れるよう変更。そもそも、tableを作成するのが苦手なのが露呈しました。

TableRow組み立て

Tr要素を作成して、TdをappendChildする。
Td要素作成はまた別関数で行う。

const getTableRowFragment = (userData, userDataKeys) => {
  const tableRowfragment = document.createDocumentFragment();
  for (let i = 0; i < userData.length; i++) {
    const tr = createElementWithClassName("tr", "tr"); 
    tableRowfragment.appendChild(tr).appendChild(getTableDataFragment(userData[i]));
  }
  return tableRowfragment;
}

const getTableDataFragment = (userData) => {
  const tableDatafragment = document.createDocumentFragment();
  Object.keys(userDataColumn).forEach((key) => {
    const td = createElementWithClassName("td", "td");
    td.textContent = userData[key];
    tableDatafragment.appendChild(td);
  });
  return tableDatafragment;
};

//当初のコード
// const getTableDataFragment = (userData,userDataKeys) => {
//   const tableDatafragment = document.createDocumentFragment(); 
//   for (let i = 0; i < userDataKeys.length; i++) {
//   const td = createElementWithClassName("td", "td");
//   td.textContent = userData[userDataKeys[i]];
//   tableDatafragment.appendChild(td);
// }
//   return tableDatafragment; 
// }

レビューPOINT

Td要素の作成については、当初for文を使用し、userDataColumnで取得したkeyを使用してほしいデータを取得していました。
しかし、forEachを使用すれば、keyを自然に取得でき、かつ、可読性も高くなるとレビューいただきました。
forEachを使用するアイディアが全くなかったのですが、無駄な引数を渡す必要もなくなりスッキリ、目から鱗でした。

前回の課題にて、適切なfor文を使用するのがいいと学んだばかりでしたが、また1つ知識が増え嬉しい反面、勉強不足も実感。loopについてももっと勉強せねば。

その他レビューPOINT

ずっと前から使用しているローディング画像表示の関数にて、jsで表示させているのでjs-の接頭辞をつけた方が良いのではとご指摘いただきました。本当にその通りですね、なぜに今まで気づかなかったんかと思いました。気づきをいただき感謝です。

const showLoadImg = () => {
  const loadImg = createElementWithClassName("img", "loading");
  loadImg.src = "./img/loading-circle.gif";
  loadImg.id = 'js-loading';
  wrapper.appendChild(loadImg);
} 

const removeLoadImg = () => {
  document.getElementById('js-loading').remove();
} 

後記

HTMLで書くときでさえも苦手なTable作成でしたが、適当な知識しかないことが露呈しましたが、データを受け取って、必要な要素で組み立てるなど、新しい方法を教わったり、こんなふうにもできるのかと勉強になりました。
loopについてはもっと知識を入れる必要があるなと感じました。

c.sakyou

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA