0

I am working on a project which moves project from on list to another. Here I have implemented a js for this projects 'Finish' and 'Activate' buttons which will switch them from 'Active Projects' to 'finished Projects' and vice versa.

class DOMHelper {
  // Invoked using class
  static clearEventListeners(element) {
    // Deep copy the all the decendents of the element.
    const clonedElement = element.cloneNode(true);

    // Replacing the element with cloned Element
    element.replaceWith(clonedElement);

    // Return the clonedElement
    return clonedElement;
  }

  // Invoked using class
  static moveElement(eId, newDestSelector) {
    // Get element Id of the source list
    const element = document.getElementById(eId);

    // Select the DOM of the destionation
    const destElement = document.querySelector(newDestSelector);

    // Appends the element to destination list
    destElement.append(element);
  }
}

class Tooltip {}

class ProjectItem {
  constructor(id, updatePListFunc, type) {
    this.id = id;
    this.updatePListHandler = updatePListFunc;
    this.connectSwitchBtn(type);
  }


  connectSwitchBtn(type) {
    // Select the id of the list item
    const pItemElement = document.getElementById(this.id);

    // Selecting 'Finish' or 'Activate' button
    let switchBtn = pItemElement.querySelector('button:last-of-type');

    // Reset the event listeners after switching
    switchBtn = DOMHelper.clearEventListeners(switchBtn);

    // Set the type of the button according to the list type
    switchBtn.textContent = type === 'active' ? 'Finish' : 'Activate';

    // Adding eventListner
    switchBtn.addEventListener('click', this.updatePListHandler.bind(null, this.id));
  }

  update(updatePListFunc, type) {
    this.updatePListHandler = updatePListFunc;
    this.connectSwitchBtn(type);
  }
}

class ProjectList {
  // Property
  projects = []; // Empty list for the projects

  // Active or Finished type
  constructor(type) {
    this.type = type;
    const pItems = document.querySelectorAll(`#${type}-projects li`);

    // Iterate all list items
    for (const pItem of pItems) {
      // Put them into the projects array
      this.projects.push(
        // Creates new obj
        // with id of list item, a function, and its type
        // Initializes and stores the project items for the list
        new ProjectItem(pItem.id, this.switchProject, this.type)
      );
    }
    console.log(this.projects);
  }

  // Sets switch handler function for the project List.
  setSwitchHandlerFunc(switchHandlerFunc) {
    // Refers to the current instance of ProjectList class
    // Calling setSwitchHandlerFunc
    this.switchHandler = switchHandlerFunc;
  }


  // Adds project to a List
  addProject(project) {
    // Push the new project into the array
    this.projects.push(project);

    // Moves the project form one list to another 
    DOMHelper.moveElement(project.id, `#${this.type}-project ul`);

    // Update the project list
    // Requires the type of the item and function
    project.update(this.switchProject.bind(this), this.type);
  }

  // Switches projects from one list to another
  switchProject(pId) {
    // Select the list item to be removed
    this.setSwitchHandlerFunc(this.projects.find(p => p.id === pId));

    // Removes list item from one list
    this.projects = this.projects.filter(p => p.id !== pId);
  }
}

class App {
  // Invoked using class.
  static init() {
    // creating instances for active and finished projects.
    const activeProjectsList = new ProjectList('active')
    const finishedProjectsList = new ProjectList('finished');

    // Active project points to finished project
    // When clicked on Finish
    activeProjectsList.setSwitchHandlerFunc(
      finishedProjectsList.addProject.bind(finishedProjectsList)
    );

    // Finished project points to active project
    // When clicked on Activate
    finishedProjectsList.setSwitchHandlerFunc(
      activeProjectsList.addProject.bind(activeProjectsList)
    );
  }
}

// calls the static method.
App.init();
* {
  box-sizing: border-box;
}

html {
  font-family: sans-serif;
}

body {
  margin: 0;
}

#main-header {
  width: 100%;
  height: 6rem;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #ff0062;
}

#main-header h1 {
  color: white;
  margin: 0;
}

footer {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  text-align: center;
}

ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

li {
  margin: 1rem 0;
}

section {
  margin: 1rem auto;
  width: 40rem;
  max-width: 90%;
}

section ul {
  padding: 1rem;
  max-height: 20rem;
  overflow: scroll;
}

section>h2 {
  color: white;
  margin: 0;
}

button {
  font: inherit;
  background: #ff0062;
  color: white;
  border: 1px solid #ff0062;
  padding: 0.5rem 1.5rem;
  cursor: pointer;
}

button.alt {
  background: white;
  color: #ff0062;
}

button:focus {
  outline: none;
}

button:hover,
button:active {
  background: #ff2579;
  border-color: #ff2579;
  color: white;
}

.card {
  border-radius: 10px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26);
  padding: 1rem;
  background: white;
}

#active-projects {
  border: 1px solid #870099;
}

#active-projects>header {
  background: #870099;
  padding: 1rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

#active-projects header h2 {
  color: white;
  margin: 0;
}

#finished-projects {
  border: 1px solid #535353;
}

#finished-projects>header {
  background: #535353;
  padding: 1rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

#finished-projects header h2 {
  color: white;
  margin: 0;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>Project Board</title>
  <link rel="stylesheet" href="assets/styles/app.css" />
  <script src="assets/scripts/app1.js" defer></script>
</head>

<body>
  <header id="main-header">
    <h1>Project Planner</h1>
  </header>
  <section id="active-projects">
    <header>
      <h2>Active Projects</h2>
    </header>
    <ul>
      <li id="p1" data-extra-info="Got lifetime access, but would be nice to finish it soon!" class="card">
        <h2>Finish the Course</h2>
        <p>Finish the course within the next two weeks.</p>
        <button class="alt">More Info</button>
        <button>Finish</button>
      </li>
      <li id="p2" data-extra-info="Not really a business topic but still important." class="card">
        <h2>Buy Groceries</h2>
        <p>Don't forget to pick up groceries today.</p>
        <button class="alt">More Info</button>
        <button>Finish</button>
      </li>
    </ul>
  </section>
  <section id="finished-projects">
    <header>
      <h2>Finished Projects</h2>
    </header>
    <ul>
      <li id="p3" data-extra-info="Super important conference! Fictional but still!" class="card">
        <h2>Book Hotel</h2>
        <p>
          Academind conference takes place in December, don't forget to book a hotel.
        </p>
        <button class="alt">More Info</button>
        <button>Activate</button>
      </li>
    </ul>
  </section>
</body>

</html>

I am getting this error.

app1.js:106 Uncaught TypeError: Cannot read properties of null (reading 'setSwitchHandlerFunc')
    at switchProject (app1.js:106:14)

I am not able to understand why correct context of 'this' is getting lost in the loop?

  • You're losing the `this` context here: `new ProjectItem(pItem.id, this.switchProject, this.type)`. Passing just `this.switchProject` means it'll have no `this` context when called. – deceze Jul 08 '23 at 12:16
  • @deceze, Isn't there any tool available to visualize the 'this' keyword because in theory it is understandable however when I am trying to practically check in the dev tools. It is not very clear. understanding this has become a huge hurdle for me. – Mr.Unforgettable Jul 08 '23 at 12:20
  • Not sure if http://pythontutor.com might help. – deceze Jul 08 '23 at 12:24
  • @deceze, Let me try and see. Also one thing why should I post the error text rather than screenshot. I am really curious to learn the decorum as I am new this platform. – Mr.Unforgettable Jul 08 '23 at 12:33
  • https://meta.stackoverflow.com/q/285551/476 – deceze Jul 08 '23 at 13:39
  • I see. Thank you sir for your time. – Mr.Unforgettable Jul 08 '23 at 13:48

0 Answers0