現在、もりけん塾にてJavaScriptを勉強させていただいております。その記録。
今回は課題20についての備忘録です。
考え方が間違っている箇所もあるかと思いますが、お気づきの際はご指摘いただければと思います。
課題20について
仕様
- こちらのようなテーブルを画面遷移してから3秒後に解決されるPromiseが返すオブジェクトを元に作ってください。
- カラム名など(id, 名前等)もdataで表現して受け取り、フロント側で加工して表示すること
- APIデータのidはリアルではない採番や、別idを付与しても良い
- その時、idは要素の並び順でつけず以下のように順不同にしてください
制作物
コードはこちらから(codesandbox)※codesandboxではエラーが出る場合がありますが、リロードすれば動きます。
実装内容
JSONデータの作成
まずはJSONデータを作成。下記のようにしました。
{
"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