skip to Main Content

i’m new to javascript and i’m trying to create a page where the entry titles will be on the left (the sidebar) and when clicked, the content will appear on the right (main). the problem is that the content is appearing directly below the title, not by its side.
i tried changing the content to the div it’s supposed to be in and when i click the title nothing even happens. any ideas on how to fix this?

var entries = document.querySelectorAll(".entry");
for (var i = 0; i < entries.length; i++) {
  var el = entries[i];
  el.addEventListener("click", function () {
    var itemId = i;
    var allEntries = document.querySelectorAll(".entry");
    if (this.nextElementSibling.className.match("show")) {
      this.nextElementSibling.classList.remove("show");
    } else {
      this.nextElementSibling.classList.add("show");
    }
    for (var j = 0; j < allEntries.length; j++) {
      if (this == allEntries[j]) {
        continue;
      }
      allEntries[j].nextElementSibling.classList.remove("show");
    }
  });
}
.entry {
  color: #d49a95;
  cursor: pointer;
  padding: 10px;
}

.entry-content {
  display: none;
}

.show {
  display: block;
}
<div class="main">
  <div class="sidenav">
    <div class="entry">test</div>
    <div class="entry">test2</div>
  </div>
  <main>
    <center>
      <p class="entry-content">helloo</p>
      <p class="entry-content">hiiii</p>
    </center>
  </main>
</div>

2

Answers


  1. The issue is because you’re using nextElementSibling() from the clicked .entry elements, yet they have no sibling. From the description of the issue it looks like you’re trying to access the related .entry-content elements, however they are children of a sibling to the parent of the .entry.

    To simplify the issue you could relate them by index within their respective parent elements, like this:

    const entries = document.querySelectorAll(".entry");
    const contents = document.querySelectorAll('.entry-content');
    
    const getChildIndex = el => [].indexOf.call(el.parentNode.children, el);
    const hideAllContent = () => contents.forEach(c => c.classList.remove('show'));
    
    entries.forEach(entry => {
      entry.addEventListener('click', e => {
        hideAllContent();
        
        const index = getChildIndex(e.target);
        contents[index].classList.add('show');
      });
    });
    .entry {
      color: #d49a95;
      cursor: pointer;
      padding: 10px;
    }
    
    .entry-content {
      display: none;
    }
    
    .show {
      display: block;
    }
    <div class="main">
      <div class="sidenav">
        <div class="entry">test</div>
        <div class="entry">test2</div>
      </div>
      <main>
        <center>
          <p class="entry-content">helloo</p>
          <p class="entry-content">hiiii</p>
        </center>
      </main>
    </div>

    Or alternatively you could use data attributes on the .entry elements to directly specify which .entry-content should be displayed:

    const entries = document.querySelectorAll(".entry");
    const contents = document.querySelectorAll('.entry-content');
    const hideAllContent = () => contents.forEach(c => c.classList.remove('show'));
    
    entries.forEach(entry => {
      entry.addEventListener('click', e => {
        hideAllContent();
        document.querySelector(e.target.dataset.content).classList.add('show');
      });
    });
    .entry {
      color: #d49a95;
      cursor: pointer;
      padding: 10px;
    }
    
    .entry-content {
      display: none;
    }
    
    .show {
      display: block;
    }
    <div class="main">
      <div class="sidenav">
        <div class="entry" data-content="#content-a">test</div>
        <div class="entry" data-content="#content-b">test2</div>
      </div>
      <main>
        <center>
          <p class="entry-content" id="content-a">helloo</p>
          <p class="entry-content" id="content-b">hiiii</p>
        </center>
      </main>
    </div>

    Also, as an aside, using things like cursor: pointer to make a non-clickable element behave like a clickable element is very bad practice. I would strongly suggest you change the .entry elements to <a />, calling preventDefault() if you don’t want the links to actually go anywhere.

    Login or Signup to reply.
  2. HTML:
    Since I’ve changed the JavaScript entirely, I added the onclick="showWindow(n)" attribute to the .entry navigation buttons. And on the .entry-content divs, I’ve added data-window:n attributes. Now the good thing about this is, you can add as many nav items and content windows as you want. What you have to do is just

    • Make a navigation button (.entry) and add the showWindow(n) attribute as well but replace n with a number, e.g. 4 since it has not been used before.
    • Make a content window (.entry-content), and give it the data-window:"n" attribute, where n is same as the n in the navigation button, so 4 in this case.

    Now when you click the navigation button with the showWindow(4) attribute, it’ll show the content window with data-window="4" attribute. Also added a close button.

    CSS:
    Declared styles for the close button. Used flex-box on .main to display content window next to the navigation bar. flex: 2; property on main so it takes up all the available space.

    Javascript:
    So I’ve made a lot of changes here. Honestly, a completely different approach to get the desired result. The code you attached, returns errors when ran. Hence, I’ve rewritten the entire JavaScript code.

    • Cross Event-listener
      On clicking the cross button, .active class is removed from all elements.
    • showWindow(n) Function
      When called, The element with data-attribute=n is stored in the window variable. Then a loop runs which removes .active class from all content windows.
      .active class is then added to .cross and the window stored in window variable.
    let entries = document.querySelectorAll(".entry");
    let windows = document.querySelectorAll("[data-window]");
    let cross = document.querySelector(".close");
    
    cross.addEventListener("click", () => {
      for (let i = 0; i < windows.length; i++) {
        windows[i].classList.remove("active");
      }
      cross.classList.remove("active");
    });
    
    function showWindow(n) {
      let window = document.querySelector(`[data-window="${n}"]`);
      for (let i = 0; i < windows.length; i++) {
        windows[i].classList.remove("active");
      }
      cross.classList.add("active");
      window.classList.add("active");
    }
    body,
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    .main {
      display: flex;
    }
    
    .sidenav {
      padding: 0 10px;
    }
    
    main {
      position: relative;
      flex: 2;
      padding: 0 10px;
    }
    
    .entry {
      color: #d49a95;
      cursor: pointer;
      padding: 15px;
    }
    
    .entry-content {
      position: absolute;
      top: 0;
      left: 0;
      padding: 0 10px;
      visibility: hidden;
    }
    
    .entry-content.active {
      visibility: visible;
    }
    
    .show {
      display: block;
    }
    
    .close {
      display: grid;
      place-items: center;
      --size: 18px;
      position: absolute;
      right: 0px;
      top: 0px;
      width: 30px;
      height: 30px;
      opacity: 0;
      cursor: pointer;
    }
    
    .close.active {
      opacity: 0.7;
    }
    
    .close.active:hover {
      opacity: 1;
    }
    
    .close:before,
    .close:after {
      position: absolute;
      content: "";
      height: var(--size);
      width: 2px;
      background-color: #333;
    }
    
    .close:before {
      transform: rotate(45deg);
    }
    
    .close:after {
      transform: rotate(-45deg);
    }
    <body>
      <div class="main">
        <div class="sidenav">
          <div class="entry" onclick="showWindow(1)">Window 1</div>
          <div class="entry" onclick="showWindow(2)">Window 2</div>
          <div class="entry" onclick="showWindow(3)">Window 3</div>
        </div>
        <main class="container">
          <p class="entry-content" data-window="1">Content 1</p>
          <p class="entry-content" data-window="2">Content 2</p>
          <p class="entry-content" data-window="3">Content 3</p>
          <i class="close"></i>
        </main>
      </div>
    </body>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search