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>
>Solution :
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.