1

I am trying to use JavaScript to dynamically change the right margin for a horizontal list. I have created a variable called "space" that equals the margin quantity that I want. Now I need to make the right margin for each list item equal to the "space" variable.

To be more specific, I'm having trouble with how to reference the list items within my JavaScript file. I can reference elements by class and id using getElementsByClassName and getElementById, respectively, but I really need to refer to an <a> link within a class. That is, in css I could manually modify the margin with:

.menu-item a {
  margin: 0 50px 0 0;   
}

Notice I need the "a" in the css selector reference. How do I get this reference into Javascript?

Here is some html:

  <div class="container" id="container">
    <ul>
      <li class="menu-item" id="menuItem"><a href="item0.html">Item 0</a></li>
      <li class="menu-item" id="menuItem"><a href="item1.html">Item 1</a></li>
      <li class="menu-item" id="menuItem"><a href="item2.html">Item 2</a></li>
      <li class="menu-item" id="menuItem"><a href="item3.html">Item 3</a></li>
      <li class="menu-item" id="menuItem"><a href="item4.html">Item 4</a></li>
      <li class="menu-item" id="menuItem"><a href="item5.html">Item 5</a></li>
    </ul>
  </div>

And here is some css:

.container{
  width:auto;
  margin-left:10%;
  margin-right: 10%;
}

.menu-item a {
  color: #000000;
  font-family: sans-serif;
  font-size: 16px;
  float:left;    
}

And here is some javascript:

var space = (document.getElementById("container").offsetWidth - 450)/6;

var menuItem = document.getElementsByClassName("menu-item"); /*this line is the problem*/

spacer();
function spacer () {
  menuItem.style.margin = "0 " + space + "px 0 0"; /*and this line is potentially incorrect as well*/
}

As requested, I will take this opportunity to mention that I am after a solution that is compatible with all browsers. Thanks

Alexander Nied
  • 12,804
  • 4
  • 25
  • 45
Normajean
  • 1,075
  • 3
  • 11
  • 28
  • 2
    Why are you assigning the same `ID` attribute to different tag elements? Each `ID` attribute should be unique to each individual tag element. – Manuel Abascal Oct 11 '19 at 02:07
  • `document.querySelector(".menuItem a");` – Snel23 Oct 11 '19 at 02:08
  • is there a solution that's compatible with all browsers? – Normajean Oct 11 '19 at 02:11
  • @Normajean Snel23 solution should be compatible with all modern browsers – Manuel Abascal Oct 11 '19 at 02:11
  • @ManuelAbascal I noticed that when I copied it over. Is there anything wrong with doing so? – Normajean Oct 11 '19 at 02:13
  • 1
    @ManuelAbascal https://www.w3schools.com/jsref/met_document_queryselector.asp I need something that is compatible with all browsers – Normajean Oct 11 '19 at 02:13
  • @Normajean I might not understand which browser do you need to support, but `document.querySelector()` comptability is pretty good https://caniuse.com/#feat=queryselector – Manuel Abascal Oct 11 '19 at 02:15
  • There is nothing wrong with using it, as long as you use it correctly. It will only return the first result it finds, but if you want all of them use `document.querySelectorAll(".menuItem a")` which returns an array of all matches – Snel23 Oct 11 '19 at 02:16
  • I want something compatible with all browsers. Yes this includes IE 6 & 7. – Normajean Oct 11 '19 at 02:17
  • Change your question to add this information, because otherwise people will not assume such requirements – Snel23 Oct 11 '19 at 02:18
  • 1
    [Here](https://stackoverflow.com/questions/28194786/how-to-make-document-queryselector-work-in-ie6) is a question about using `document.querySelector()` in IE 6. Note: the top answer suggests to no longer support IE6 any longer (it is extremely outdated.. the answer suggests to no longer support it and it was posted in 2015..) but does provide a workaround – Snel23 Oct 11 '19 at 02:21
  • @Snel23 I wouldn't suggest you to worry about compatibility for IE 6 - 8, imagine doing all the workarounds for every single function that you write – Manuel Abascal Oct 11 '19 at 02:26
  • @ManuelAbascal I can't change my project scope. – Normajean Oct 11 '19 at 03:23
  • @Normajean - how are you testing in IE6? – Alexander Nied Oct 11 '19 at 03:24
  • Are you guys saying there is no other way to refer to a link in a html file using javascript other than document.querySelector() ? – Normajean Oct 11 '19 at 03:24
  • No, there is a workaround as provide it by @Snel23 but we wouldn't suggest you to support these older browsers, but if you actually have to do this for whatever reason, use his link as a pointer, good luck! – Manuel Abascal Oct 11 '19 at 03:28
  • @Normajean - most of what you wish to be done can probably be done in IE6-- however, it may be difficult and involve a lot of troubleshooting-- IE6 is a very old browser. Honestly, while I am hesitant to recommend jQuery, the easiest thing for you may be to leverage jQuery 1.12 if you _really_ need to support IE6. That said, I am going to take a crack and see if I can find something that will probably work in IE6-- although I don't currently have a great way to test for IE6. – Alexander Nied Oct 11 '19 at 03:29

1 Answers1

2

OK, I believe that this will work for you. I do not have a great way to test in IE6 right now, but the code being used should be compatible with IE6.

In the demo below, I create a function called updateAnchorMarginsTo that accepts a number and sets the left margin of all the anchors to the number passed. For the demo I then have it toggle every second between setting the left margin to 0 and to 20.

(I also removed all the duplicate id values, as that is invalid HTML and is sure to generate problems).

First, we check to see if document.getElementsByClassName is defined-- if not, we might be in an older browser. We polyfill it with this helpful SO answer.

Inside updateAnchorMarginsTo we can then use getElementsByClassName to get all the li elements with the menu-item class. We use a for loop to iterate over each of those li elements and leverage document.getElementsByTagName (supported in IE6) to fetch all a elements that li might contain, and grab the first one (we know there will only be one). Finally, we update the style attribute of each of those anchors, which is supported in older IE.

if (!document.getElementsByClassName) {
  // if we are below IE9 we have to polyfill getElementsByClassName...
  // This solution courtesy of:
  // https://stackoverflow.com/questions/6584635/getelementsbyclassname-doesnt-work-in-old-internet-explorers-like-ie6-ie7-i
  document.getElementsByClassName = function(cl) {
    var retnode = [];
    var elem = this.getElementsByTagName('*');
    for (var i = 0; i < elem.length; i++) {
      if((' ' + elem[i].className + ' ').indexOf(' ' + cl + ' ') > -1) retnode.push(elem[i]);
    }
    return retnode;
  }; 
}

function updateAnchorMarginsTo(numPixels) {
  var menuListItems = document.getElementsByClassName("menu-item");
  var currentMenuAnchor, currentMenuListItem;

  for (var i = 0; i < menuListItems.length; i++) {
      currentMenuListItem = menuListItems[i];
      currentMenuAnchor = currentMenuListItem.getElementsByTagName("a")[0];
      currentMenuAnchor.style.marginLeft = numPixels.toString() + 'px';
  }
}

var margins = 0;

setInterval(function () {
  margins = margins === 0 ? 20 : 0;
  updateAnchorMarginsTo(margins);
}, 1000);
<div class="container" id="container">
    <ul>
        <li class="menu-item"><a href="item0.html">Item 0</a></li>
        <li class="menu-item"><a href="item1.html">Item 1</a></li>
        <li class="menu-item"><a href="item2.html">Item 2</a></li>
        <li class="menu-item"><a href="item3.html">Item 3</a></li>
        <li class="menu-item"><a href="item4.html">Item 4</a></li>
        <li class="menu-item"><a href="item5.html">Item 5</a></li>
    </ul>
</div>

Give it a try-- like I said, I don't have IE6 testing infrastructure setup, so I am interested to see if this works.

IE6 is, at this point, an ancient browser. If you must support it, it will take some effort. If possible, it may be wise to lean on an older jQuery version to assist you. Good luck!

Alexander Nied
  • 12,804
  • 4
  • 25
  • 45