Jlouk Jlouk - 2 months ago 12
HTML Question

Conditionally open links in a new tab

My goal is to make these links open in a new tab only if the check box is ticked.

Why is my anchor.getAttribute not a function if I change getElementByID to getElementsByClassName?

<!DOCTYPE html>
<html>
<head> </head>
<title> </title>
<body>
<input id="checkr" type="checkbox">Open in New Window</input>
<br />
<a href="http://www.google.com" class="linker">Google</a> <br>
<a href="http://www.w3schools.com" class="linker">W3 Schools</a> <br>
<a href="http://www.twitch.tv" class="linker">Twitch</a> <br>

<script>
var checkr = document.getElementById('checkr');
var anchor = document.getElementsByClassName('linker');
var link = anchor.getAttribute('href');

function OpenWindow(href) {
if (checkr.checked) {
window.open(href, '_blank');
} else {
window.open(href, '_self');
}
}
anchor.onclick = function() {
OpenWindow(link);
return false;
};
</script>
</body>
</html>

Answer

First, getElementsByClassName returns an array-like object...elements plural should be a clue...it's not returning a single thing, it's returning a collection of thing.

So to attach your handlers, you need to loop over them like so:

const linkers = document.getElementsByClassName('linker');
for(const linker of linkers) {
  linker.addEventListener('click', function(evt) {
    // this is your click event listener
  });
}

Second, the way you're trying to get the anchor isn't going to work, because which anchor are you talking about? The best way to do it is let the event itself tell you what anchor was clicked, which it does through it's target property:

const linkers = document.getElementsByClassName('linker');
for(const linker of linkers) {
  linker.addEventListener('click', function(evt) {
    const href = evt.target.attributes['href'].value;
  });
}

Since you don't want the default behavior to happen, call evt.preventDefault():

const linkers = document.getElementsByClassName('linker');
for(const linker of linkers) {
  linker.addEventListener('click', function(evt) {
    evt.preventDefault();
    const href = evt.target.attributes['href'].value;
  });
}

Then finally you can get the value of the checkbox and take the appropriate action:

const linkers = document.getElementsByClassName('linker');
for(const linker of linkers) {
  linker.addEventListener('click', function(evt) {
    evt.preventDefault();
    const href = evt.target.attributes['href'].value;
    const newWindow = document.getElementById('checkr').checked;
    window.open(href, newWindow ? '_blank' : '_self');
  });
}

Note that I'm using for...of loops, which may not be available in manky old browsers. If that's a problem, you can replace them with regular for loops with indices (you can't use Array#forEach because the DOM, in its infinite wisdom [cough] doesn't return arrays, but array-like objects).