93 lines
2.6 KiB
Org Mode
Executable File
93 lines
2.6 KiB
Org Mode
Executable File
#+TITLE: Understands the Javascript language
|
|
#+OPTIONS: num:nil
|
|
#+DATE: <2026-03-11 Wed 16:52>
|
|
#+filetags: :learning:notes:
|
|
#+WIP:
|
|
#+COMMENTS: t
|
|
#+SLUG: understands-the-javascript-language
|
|
|
|
* JS - Competency Log
|
|
To evidence this competency I wanted to use a comment system that I
|
|
implemented for my website. The goal was to fetch comments from an API,
|
|
render them dynamically and support nested replies.
|
|
|
|
** Working with the DOM
|
|
A key part of front end JS development is manipulating the DOM (Document
|
|
Object Model). I dynamically created comment elements using
|
|
=document.createElement= rather than injecting raw HTML. This approach
|
|
avoids security issues such as cross-site scripting (XSS).
|
|
|
|
As an example:
|
|
|
|
#+begin_src js
|
|
const wrapper = document.createElement("div");
|
|
wrapper.className = "comment";
|
|
|
|
const author = document.createElement("strong");
|
|
author.textContent = comment.author || "Anonymous";
|
|
#+end_src
|
|
|
|
Using textContent ensures that any user submitted content is safely
|
|
rendered as text instead of HTML.
|
|
|
|
** Data structures
|
|
Comments returned from the backend are stored as a flat array, but
|
|
replies must be displayed as a nested tree structure. To solve this, I
|
|
implemented the buildCommentTree function.
|
|
|
|
#+begin_src js
|
|
const byId = {};
|
|
const roots = [];
|
|
#+end_src
|
|
|
|
I use the JS object =byId= as a lookup table (O(1) complexity) to access
|
|
comments by ID. This ensures that I can quickly find the parent of a
|
|
comment. I then use the roots array to store the top-level comments,
|
|
which are the ones without a parent ID.
|
|
|
|
#+begin_src js
|
|
const parent = byId[comment.parent_id];
|
|
if (parent) parent.children.push(comment);
|
|
#+end_src
|
|
|
|
** Async programming
|
|
Modern front-end applications frequently communicate with APIs. I used
|
|
async/await to handle asynchronous operations when fetching and posting
|
|
comments.
|
|
|
|
#+begin_src js
|
|
async function fetchComments() {
|
|
const res = await fetch(`/api/comments/${pageSlug}`);
|
|
return await res.json();
|
|
}
|
|
#+end_src
|
|
|
|
I used async/await instead of promise chaining to make the code more
|
|
readable and easier to understand. I also added some response
|
|
validations:
|
|
|
|
#+begin_src js
|
|
if (!res.ok) {
|
|
console.error("Failed to fetch comments");
|
|
}
|
|
#+end_src
|
|
|
|
** Event Handling
|
|
JS event handling was used to respond to user interactions, such as
|
|
submitting a comment or replying.
|
|
|
|
#+begin_src js
|
|
form.addEventListener("submit", async event => {
|
|
event.preventDefault();
|
|
#+end_src
|
|
|
|
Calling preventDefault() prevents the browser from reloading the page
|
|
during form submission, allowing the comment system to update
|
|
dynamically instead.
|
|
|
|
Also the same for replies:
|
|
|
|
#+begin_src js
|
|
replyBtn.onclick = () => showReplyForm(wrapper, Number(comment.id));
|
|
#+end_src
|