search

Home  >  Q&A  >  body text

Scroll event listener added to element but only moves correctly if scrollTop is not equal to 0

So I wrote this little script in which there are two lists - Completed/Active Tasks, you can switch the task list by clicking the button, and you can read more information about the task by clicking "More Info". When more info is clicked, a new div element is created and I want to follow its host element's Y position, and it works half way. This is what it looks like: Enter image description here

This is a bug, I'm pretty sure this error occurs when the scrollable element scrollTop is not 0 (it is created the right way and whenever I start scrolling it Jump up immediately and cover the mission itself): Enter image description here.

This is the part of my code that is responsible for identifying the px amount of scrolling, the scroll direction and moving the "more info" div element, and the part responsible for creating it, I don't know where this is the problem because I have no idea about I'm still new to coding overall, and I'm not very familiar with css/html.

createTooltip() {
    const tooltipElement = document.createElement('div');
    tooltipElement.className = 'card';
    const toolTipTemplate = document.getElementById('tooltip');
    const tooltipBody = document.importNode(toolTipTemplate.content, true);
    tooltipBody.querySelector('p').textContent = this.text;
    tooltipElement.append(tooltipBody);

    const hostElPosLeft = this.hostElement.offsetLeft;
    const hostElPostop = this.hostElement.offsetTop;
    const hostElHeight = this.hostElement.clientHeight;
    const parentElementScrolling = this.hostElement.parentElement.scrollTop;

    const x = hostElPosLeft + 20;
    const y = hostElPostop + hostElHeight - parentElementScrolling - 10;
    tooltipElement.style.position = 'absolute';
    tooltipElement.style.left = x + 'px';
    tooltipElement.style.top = y + 'px';

    const scrollHandler = () => {
      ulElement.addEventListener('scroll', yLogger);
    };
    tooltipElement.addEventListener('click', this.closeToolTip);
    tooltipElement.addEventListener('click', scrollHandler);
    this.element = tooltipElement;
    const ulElement = this.hostElement.parentElement;
    console.log(ulElement);

    let pxPosition = [0];
    let currentY = y;

    const yLogger = () => {
      let scrollDirection;
      let pxScrolled = 0;
      if (pxPosition.length <= 1) {
        pxPosition.push(ulElement.scrollTop);
      } else {
        pxPosition.push(ulElement.scrollTop);
        pxPosition.shift(ulElement);
      }
      console.log(pxPosition);
      if (pxPosition[1] < pxPosition[0]) {
        scrollDirection = 'up';
        pxScrolled = pxPosition[0] - pxPosition[1];
      } else if (pxPosition[0] < pxPosition[1]) {
        scrollDirection = 'down';
        pxScrolled = pxPosition[1] - pxPosition[0];
      }
      console.log(pxScrolled);
      console.log(scrollDirection);

      if (scrollDirection === 'down') {
        currentY = currentY - pxScrolled;
        console.log(currentY);
        tooltipElement.style.top = currentY + 'px';
      } else {
        scrollDirection === 'up';
        currentY = currentY + pxScrolled;
        console.log(currentY);
        tooltipElement.style.top = currentY + 'px';
      }
    };

    this.hostElement.closest('ul').addEventListener('scroll', yLogger);
  }
}

I'm adding the HTML and CSS snippets, although I don't think they're necessary since it was written by the instructor of the course I'm taking.

This is the HTML snippet:

<!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/app.js" defer></script>
  </head>
  <body>
    <template id="tooltip">
      <h2>More Info</h2>
      <p></p>
    </template>
    <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"
          draggable="true"
        >
          <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"
          draggable="true"
        >
          <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"
          draggable="true"
        >
          <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>
    <footer>
      <button id="im-done-btn">I'm Done!</button>
    </footer>
  </body>
</html>

Here is the relevant CSS snippet:

* {
  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;
}

.droppable {
  background: #ffe0ec
}

#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;
}

P粉427877676P粉427877676265 days ago610

reply all(1)I'll reply

  • P粉885035114

    P粉8850351142024-04-02 00:20:03

    This problem can be solved with CSS, you can remove the following from the Javascript code:

    tooltipElement.style.position = 'absolute';
    tooltipElement.style.left = x + 'px';
    tooltipElement.style.top = y + 'px';

    Instead, change the CSS by adding the following:

    li.card {
        position: relative;
    }
    div.card {
        position: absolute;
        top: 0; /* or some other value, experiment until you find the one which works for you */
        left: 0; /* same as above */
        z-index: 1;
    }

    To do this, the div.card element you create in Javascript code must be a child of the corresponding li.card element. I also (probably wrongly) assumed that your original code was similar to the code I found earlier and posted it in the comments of your question since I couldn't run your original code.

    Your position:absolute initially doesn't work because the li.card parent's position is not explicitly set and defaults to static.

    EditForgot to mention the z-index bit. This is required because your infobox won't be fully visible (it will be under the next li.card element).

    reply
    0
  • Cancelreply