Client-Side Web Application Development Examples

Classified in Computers

Written on in English with a size of 8.49 KB

Client-Side Web Application Logic

Course Registration Script

This script handles the client-side logic for a course registration form. It fetches available courses, populates a selection dropdown, and processes form submissions to register new entries via an API.

DOM Element Selection and Initialization

The script begins by selecting necessary DOM elements for interaction and notification display.

const init = async function () {
  const selectEl = document.querySelector("select");
  const formEl = document.querySelector("form");
  const notifEl = document.querySelector(".success-notif");
  const errNotifEl = document.querySelector(".fail-notif");

Notification Dismissal Logic

Functionality to close success and error notification boxes is implemented by adding an event listener to "delete" buttons, which hides their parent element.

  // Code for closing the notification boxes.
  const deleteButtons = document.querySelectorAll("button.delete");
  deleteButtons.forEach((button) => {
    button.addEventListener("click", () => {
      const parentElement = button.parentElement;
      parentElement.classList.add("is-hidden");
    });
  });

Populating Course Selection

The script fetches a list of courses from a backend API and dynamically populates a <select> element with these courses. Note: A Docker container running the backend API is required for this functionality.

  // Docker container must be running already.
  const res = await fetch("http://localhost:8080/courses");
  const data = await res.json();
  data.forEach((course) => {
    const optionEl = document.createElement("option");
    optionEl.setAttribute("value", course.code);
    optionEl.innerText = `${course.code} ${course.name}`;
    selectEl.append(optionEl);
  });

Form Submission Handling

An event listener is attached to the registration form to handle submissions. It prevents default page reload, collects form data, and sends it as a JSON payload to the /registrations API endpoint using a POST request. Success or failure notifications are displayed based on the API response.

  formEl.addEventListener("submit", async function (event) {
    // To prevent the form from reloading the page once submitted.
    event.preventDefault();
    const data = new FormData(formEl);
    const objectData = Object.fromEntries(data);

    try {
      const res = await fetch("http://localhost:8080/registrations", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(objectData),
      });
      const backendResponse = await res.json(); // Assuming backend always returns JSON
      if (res.status === 200) {
        // The record was created successfully, so we need to show the success notification box.
        notifEl.classList.remove("is-hidden");
      } else {
        // Handle non-200 responses as errors
        errNotifEl.classList.remove("is-hidden");
        console.error("Registration failed:", backendResponse);
      }
    } catch (error) {
      // Something went wrong here (e.g., network error).
      errNotifEl.classList.remove("is-hidden");
      console.error("Network or API error:", error);
    }
  });
}
init();

Course and Student Display Script (courses.js)

This script is responsible for fetching course registration data and dynamically rendering it on the page, displaying courses and their enrolled students.

Data Fetching and Container Selection

The script fetches registration data from the /registrations API endpoint and selects the container where the course sections will be appended. Note: A Docker container running the backend API is required for this functionality.

const init = async function () {
  // Docker container must be running already for this to work.
  const res = await fetch("http://localhost:8080/registrations");
  const data = await res.json();
  const sectionContainerEl = document.querySelector("#section-container");

Dynamic Content Generation

For each course in the fetched data, a new <section> element is created. This section includes an <h2> for the course title and an unordered list (<ul>) containing each enrolled student's name and ID.

  data.forEach((course) => {
    // One iteration per course.
    const sectionEl = document.createElement("section");
    sectionEl.classList.add("section");

    const h2El = document.createElement("h2");
    h2El.classList.add("title");
    h2El.innerText = `${course.code} ${course.name}`;

    const ulEl = document.createElement("ul");
    course.students.forEach((student) => {
      // Create a list item (li) per student.
      const liEl = document.createElement("li");
      liEl.innerText = `${student.name} ${student.student_id}`;
      ulEl.append(liEl);
    });

    sectionEl.append(h2El);
    sectionEl.append(ulEl); // Now add the section to the page.
    sectionContainerEl.append(sectionEl);
  });
}
init();

Blog Post Display and Interaction Script

This script dynamically loads blog posts from an API and implements a "Read More/Less" toggle functionality for each post's content.

Fetching Blog Posts

The script fetches blog post data from the /blog-posts API endpoint and selects the main container for the posts. Note: A Docker container running the backend API is required for this functionality.

const init = async function () {
  const containerElement = document.querySelector(".container");
  // The Docker container must be running for this to be successful.
  const res = await fetch("http://localhost:8080/blog-posts");
  const data = await res.json();

Dynamic Blog Post Rendering

For each blog post, a new <section> element is created. The post's name, blurb, and content are inserted using a template literal. The post name is rendered as an <h3> heading.

  data.forEach((post) => {
    // This will run for every item in the data array, and each item is a post.
    // We want to generate the HTML needed for a blog post.
    const sectionElement = document.createElement("section");
    sectionElement.classList.add("section");

    const blogPostHTML = `
      <h3 class="subtitle is-size-4 has-text-weight-bold">${post.post_name}</h3>
      <p>${post.blurb}</p>
      <p>${post.content}</p>
      <p><button class="button is-link is-rounded is-small">Read Less</button></p>
    `;
    sectionElement.innerHTML = blogPostHTML;

    // Once the section element for the current blog post is ready,
    // add it as a child to the container element.
    containerElement.append(sectionElement);
  });

Read More/Less Functionality

After all blog posts are rendered, event listeners are attached to all "Read Less/More" buttons. Clicking a button toggles its text and the visibility of the associated post content (the second <p> element within the same post's section).

  // When this point is reached, all the DOM has been added already.
  const buttons = document.querySelectorAll("button.button");
  buttons.forEach((button) => {
    button.addEventListener("click", () => {
      const currentText = button.innerText;
      if (currentText.includes("Less")) {
        button.innerText = "Read More";
      } else {
        button.innerText = "Read Less";
      }
      // Get the <p> element that belongs to the same post
      // that this button belongs to as well.
      const postSection = button.closest("section"); // Find the parent section of the button
      // Assuming the structure is <h3>, <p> (blurb), <p> (content), <p> (button)
      // We want to toggle the visibility of the content paragraph.
      const contentParagraph = postSection.querySelector("p:nth-of-type(2)"); // Select the second <p> element
      if (contentParagraph) {
        contentParagraph.classList.toggle("is-hidden");
      }
    });
  });
}
init();

Related entries: