0

I'm using the javascript from this answer but since I want it for multiple pages, sometimes with more or less divs to show/hide I would like to call the function without listing all divId's. I've tried applying the starts with selector and adding a class and calling the class but I can't make it work.

I also made a change to the divVisibility function (replacing the null to divId) because I want to always have one div visible. This works but it seems to me like the first function could be tightened because I have the same line for both if and else operations.

Any help appreciated.

Improving my question. Here's the script with my tiny edit on line 5 of the JS. It currently does work but I want to not have to include all div names ("Div1", "Div2", "Div3", etc) and check if it can be tightened any more.

var divs = ["Div1", "Div2", "Div3", "Div4"];
    var visibleDivId = null;
    function divVisibility(divId) {
      if(visibleDivId === divId) {
        visibleDivId = divId;
      } else {
        visibleDivId = divId;
      }
      hideNonVisibleDivs();
    }
    function hideNonVisibleDivs() {
      var i, divId, div;
      for(i = 0; i < divs.length; i++) {
        divId = divs[i];
        div = document.getElementById(divId);
        if(visibleDivId === divId) {
          div.style.display = "block";
        } else {
          div.style.display = "none";
        }
      }
    }
.buttons a {
  font-size: 16px;
}
.buttons a:hover {
  cursor:pointer; 
  font-size: 16px;
}
<div class="main_div">
<div class="buttons">
<a href="#" onclick="divVisibility('Div1');">Div1</a> | 
<a href="#" onclick="divVisibility('Div2');">Div2</a> | 
<a href="#" onclick="divVisibility('Div3');">Div3</a> | 
<a href="#" onclick="divVisibility('Div4');">Div4</a>
</div>
<div class="inner_div">
<div id="Div1">I'm Div One</div>
<div id="Div2" style="display: none;">I'm Div Two</div>
<div id="Div3" style="display: none;">I'm Div Three</div>
<div id="Div4" style="display: none;">I'm Div Four</div>
</div>
</div>
Alejandro Hdz
  • 71
  • 1
  • 1
  • 7

2 Answers2

1

Here is an answer where the number of anchor (<a>) tags is derived from the number of div elements in your html body. No jQuery here either.

If you give <div class="buttons"> an id and each of the inner_div divs a common class, you can then select all of the inner_div elements by class name and generate an anchor tag for them.

You can then do away with the logic of which div is visible by just setting them all to style="display: none;" and then only setting style="display: block;" on the element matching the ID of the one you clicked on.

    var divs = document.getElementsByClassName('invizdiv');

    /* 
     This bit sets up your anchor tags dynamically depending on
     how many divs you have with the class 'invizdiv'
    */
    for (var i = 0; i < divs.length; i++) {
        var listDivId = divs[i].id.slice();
        var newAnchor = document.createElement('a');
        newAnchor.innerHTML = listDivId;
        newAnchor.className = "buttons";
        newAnchor.href = '#';
        newAnchor.setAttribute('targetdiv', listDivId);
        // console.log(listDivId);
        newAnchor.addEventListener('click', function(elem, event) {
            // console.log(elem);
            // console.log(event);
            divVisibility(elem.target.getAttribute('targetdiv'));
        });
        document.getElementById('button_list').appendChild(newAnchor);
    }

    // here onwards is unchanged
    var visibleDivId = null;

    function divVisibility(divId) {
        var div;
        for (var i = 0; i < divs.length; i++) {
            div = divs[i];
            div.style.display = "none";
        }
        div = document.getElementById(divId);
        div.style.display = "block";
    }
.buttons a {
  font-size: 16px;
}

.buttons a:hover {
  cursor: pointer;
  font-size: 16px;
}
<div class="main_div">
  <div id="button_list" class="buttons">
    <!-- We'll dynamically add here later -->
  </div>
  <div class="inner_div">
    <div id="Div1" class="invizdiv">I'm Div One</div>
    <div id="Div2" class="invizdiv" style="display: none;">I'm Div Two</div>
    <div id="Div3" class="invizdiv" style="display: none;">I'm Div Three</div>
    <div id="Div4" class="invizdiv" style="display: none;">I'm Div Four</div>
  </div>
</div>
  • Sorry about that. Which browser are you using? I've tried on Chrome 65 and Edge and it works fine. Also, what about it isn't working? Do you see `Div1 Div2 Div3 Div4` followed by `I'm Div One`? After clicking the `Run code snippet` button? – Jamie Cockrill Apr 20 '18 at 17:08
  • I'm on Safari, I pressed the Run code snippet button and only got "I'm Div One" and error message: { "message": "Script error.", "filename": "", "lineno": 0, "colno": 0 } – Alejandro Hdz Apr 20 '18 at 19:07
  • Ok - I don't have a Mac to test on myself. Which version of Safari is it? If you open the javascript console does it give you any further clues as to which line in the script doesn't work? – Jamie Cockrill Apr 20 '18 at 19:31
  • Sorta old version of Safari (9.0.2) I checked the console and it says unexpected token on this line: newAnchor.addEventListener('click', (elem, event) => { – Alejandro Hdz Apr 20 '18 at 19:34
  • Try this one - i was using an arrow-function in `addEventListener` as a shortcut that might not be supported in your browser. I've put in a standard function definition which might work better. – Jamie Cockrill Apr 20 '18 at 20:00
  • Great, it works now! I wish I could accept both answers. I like this because there's less to update when adding new divs but I want the buttons to be thumbnails and that seems like it would be harder with this solution. – Alejandro Hdz Apr 20 '18 at 20:28
0

I see you work without jQuery so here is an answer without.

Loop over all inner_div children and hide them by default, then show content div 1. Afterwards the hiding and showing is handled by the click handlers.

Ofcourse this is one way of doing it.

function hideAllContent(){
  // loop over the inner_div children and hide them
  Array.prototype.forEach.call(document.getElementById('inner_div').children, function(v){
    v.style.display = 'none';
  })
}
function divVisibility(divId){
  var el = document.getElementById(divId);
  if(el){
    hideAllContent();
    el.style.display = 'block';
  }
}

hideAllContent();
divVisibility('Div1'); // open by default with this content
.buttons a {
  font-size: 16px;
}
.buttons a:hover {
  cursor:pointer; 
  font-size: 16px;
}
<div class="buttons">
  <a href="#" onclick="divVisibility('Div1');">Div1</a> | 
  <a href="#" onclick="divVisibility('Div2');">Div2</a> | 
  <a href="#" onclick="divVisibility('Div3');">Div3</a> | 
  <a href="#" onclick="divVisibility('Div4');">Div4</a>
</div>
<div id="inner_div">
  <div id="Div1">I'm Div One</div>
  <div id="Div2">I'm Div Two</div>
  <div id="Div3">I'm Div Three</div>
  <div id="Div4">I'm Div Four</div>
</div>
joopmicroop
  • 891
  • 5
  • 15
  • This seems to do what I want! but something's happening in my local version because when I load the page all four inner_div divs are visible, why would that be? – Alejandro Hdz Apr 20 '18 at 16:04
  • I have changed inner_div from class to an ID. You could have both or change the code from getElementByID to querySelector to fetch the class.. – joopmicroop Apr 20 '18 at 16:11
  • Great! My local version was still showing all four divs on page load but I put back style="display: none;" on all children except the first and now it all works as hoped. Thanks! – Alejandro Hdz Apr 20 '18 at 16:16