Home > Mobile >  Show/Hide nav bar elements
Show/Hide nav bar elements

Time:07-15

I want to click on an element to show and when I click on another one the first one to hide. I want to do this with 4 elements but this only works when I'm doing this in an order, as soon as I skip a button the elements just stack on top of each other without hiding.

Some code:

function showHomePage() {
  document.getElementById("home").style.display = "block";
}

function showSkillsPage() {
  document.getElementById("home").style.display = "none";
  document.getElementById("skills").style.display = "block";
}
    
function showProjectsPage() {
  document.getElementById("skills").style.display = "none";
  document.getElementById("projects").style.display = "block";
}
    
function showLanguagesPage() {
  document.getElementById("projects").style.display = "none";
  document.getElementById("languages").style.display = "block";
}
    
showHomePage();
#home, #skills, #projects, #languages {
  display: none;
}
<ul id="top-menu-bar">
  <li><a href="#" onclick="showHomePage()" >Home</a></li>
  <li><a href="#" onclick="showSkillsPage()" >Skills</a></li>
  <li><a href="#" onclick="showProjectsPage()" >Projects</a></li>
  <li><a href="#" onclick="showLanguagesPage()" >Languages</a></li>
</ul>
<p id="home">I'm the home page.</p>
<p id="skills">I'm the skills page.</p>
<p id="projects">I'm the projects page.</p>
<p id="languages">I'm the languages page.</p>

CodePudding user response:

You're only setting the display property of some items to none when you should be setting all the ones you don't want to see.

The items are stacking when you go out of order because your show...() functions are only setting the display property of the item before them.

Here's a sample which hides all items except the one you clicked:

function showHomePage() {
  document.getElementById("home").style.display = "block";
  document.getElementById("skills").style.display = "none";
  document.getElementById("projects").style.display = "none";
  document.getElementById("languages").style.display = "none";
}

function showSkillsPage() {
  document.getElementById("home").style.display = "none";
  document.getElementById("skills").style.display = "block";
  document.getElementById("projects").style.display = "none";
  document.getElementById("languages").style.display = "none";
}
    
function showProjectsPage() {
  document.getElementById("home").style.display = "none";
  document.getElementById("skills").style.display = "none";
  document.getElementById("projects").style.display = "block";
  document.getElementById("languages").style.display = "none";
}
    
function showLanguagesPage() {
  document.getElementById("home").style.display = "none";
  document.getElementById("skills").style.display = "none";
  document.getElementById("projects").style.display = "none";
  document.getElementById("languages").style.display = "block";
}
    
showHomePage();
#home, #skills, #projects, #languages {
  display: none;
}
<ul id="top-menu-bar">
  <li><a href="#" onclick="showHomePage()" >Home</a></li>
  <li><a href="#" onclick="showSkillsPage()" >Skills</a></li>
  <li><a href="#" onclick="showProjectsPage()" >Projects</a></li>
  <li><a href="#" onclick="showLanguagesPage()" >Languages</a></li>
</ul>
<p id="home">I'm the home page.</p>
<p id="skills">I'm the skills page.</p>
<p id="projects">I'm the projects page.</p>
<p id="languages">I'm the languages page.</p>


That fixes the issue, but it's still very repetitive. You can clean it up a little bit by introducing const reference variables for your items. This will also help a little with performance since you aren't searching the DOM for them each time you click an item.

const home = document.getElementById("home");
const skills = document.getElementById("skills");
const projects = document.getElementById("projects");
const languages = document.getElementById("languages");


function showHomePage() {
  home.style.display = "block";
  skills.style.display = "none";
  projects.style.display = "none";
  languages.style.display = "none";
}

function showSkillsPage() {
  home.style.display = "none";
  skills.style.display = "block";
  projects.style.display = "none";
  languages.style.display = "none";
}
    
function showProjectsPage() {
  home.style.display = "none";
  skills.style.display = "none";
  projects.style.display = "block";
  languages.style.display = "none";
}
    
function showLanguagesPage() {
  home.style.display = "none";
  skills.style.display = "none";
  projects.style.display = "none";
  languages.style.display = "block";
}
    
showHomePage();
#home, #skills, #projects, #languages {
  display: none;
}
<ul id="top-menu-bar">
  <li><a href="#" onclick="showHomePage()" >Home</a></li>
  <li><a href="#" onclick="showSkillsPage()" >Skills</a></li>
  <li><a href="#" onclick="showProjectsPage()" >Projects</a></li>
  <li><a href="#" onclick="showLanguagesPage()" >Languages</a></li>
</ul>
<p id="home">I'm the home page.</p>
<p id="skills">I'm the skills page.</p>
<p id="projects">I'm the projects page.</p>
<p id="languages">I'm the languages page.</p>


You can clean it up even more with the realization that you could hide all the items then show the one you want.

const all = document.querySelectorAll("#home, #skills, #projects, #languages");
const home = document.getElementById("home");
const skills = document.getElementById("skills");
const projects = document.getElementById("projects");
const languages = document.getElementById("languages");

function showHomePage() {
  all.forEach(item => item.style.display = "none");
  home.style.display = "block";
}

function showSkillsPage() {
  all.forEach(item => item.style.display = "none");
  skills.style.display = "block";
}
    
function showProjectsPage() {
  all.forEach(item => item.style.display = "none");
  projects.style.display = "block";
}
    
function showLanguagesPage() {
  all.forEach(item => item.style.display = "none");
  languages.style.display = "block";
}
    
showHomePage();
#home, #skills, #projects, #languages {
  display: none;
}
<ul id="top-menu-bar">
  <li><a href="#" onclick="showHomePage()" >Home</a></li>
  <li><a href="#" onclick="showSkillsPage()" >Skills</a></li>
  <li><a href="#" onclick="showProjectsPage()" >Projects</a></li>
  <li><a href="#" onclick="showLanguagesPage()" >Languages</a></li>
</ul>
<p id="home">I'm the home page.</p>
<p id="skills">I'm the skills page.</p>
<p id="projects">I'm the projects page.</p>
<p id="languages">I'm the languages page.</p>


As one last step, you can move this logic into a single event handler. Instead of listening for clicks on the items, listen for clicks on the NavBar itself and use the Event.target property of the event to determine which item was clicked.

You'll need to use something like custom data attributes to keep track of the id to show/hide when an item is clicked.

const targets = {
  "home": document.getElementById("home"),
  "skills": document.getElementById("skills"),
  "projects": document.getElementById("projects"),
  "languages": document.getElementById("languages")
};

function showPage(event) {
  if (!event.target.dataset.targetId) return;
  Object.values(targets).forEach(item => item.style.display = "none");
  targets[event.target.dataset.targetId].style.display = "block";
}
#skills, #projects, #languages {
  display: none;
}
<ul id="top-menu-bar" onclick="showPage(event)">
  <li><a href="#" data-target-id="home">Home</a></li>
  <li><a href="#" data-target-id="skills">Skills</a></li>
  <li><a href="#" data-target-id="projects">Projects</a></li>
  <li><a href="#" data-target-id="languages">Languages</a></li>
</ul>
<p id="home">I'm the home page.</p>
<p id="skills">I'm the skills page.</p>
<p id="projects">I'm the projects page.</p>
<p id="languages">I'm the languages page.</p>

CodePudding user response:

I completely overwrote your code to give you the ability to easily expand it.

First, I removed your inline onclick events. Set the page ID as the HREF of the links. Then I gave each page a class of page, that by default in CSS is hidden. Then a new class for active that displays the page.

the javascript adds an event listener to the parent nav then looks for an href on what was clicked. Then it goes through ALL visible pages (those that have .active) and removes active. Then it adds the active class to the target page.

This answer allows you to add, change the nav and pages as you need without needing to update your javascript.

let menuBar = document.querySelector("#top-menu-bar");

menuBar.addEventListener("click", function(e) {
  e.preventDefault();
  let nav = e.target;
  let targetPage = nav.getAttribute("href");
  if (targetPage) {
    let visible = document.querySelector(".page.active");
    if (visible) {
      visible.classList.remove("active");
    }
    let target = document.querySelector(targetPage);
    target.classList.toggle("active");
  }
});
.page {
  display: none;
}

.page.active {
  display: block;
}
<ul id="top-menu-bar">
  <li><a href="#home">Home</a></li>
  <li><a href="#skills">Skills</a></li>
  <li><a href="#projects">Projects</a></li>
  <li><a href="#languages">Languages</a></li>
</ul>
<p  id="home">I'm the home page.</p>
<p  id="skills">I'm the skills page.</p>
<p  id="projects">I'm the projects page.</p>
<p  id="languages">I'm the languages page.</p>

  • Related