3

Vanilla JS. Trying to run a function on click of an element if the body tag has a class of example. No jQuery solutions please, I come from jQuery and want to learn and understand this simple task in JavaScript.

More so if you care to let me know, where is the error in my thinking please? Do I need to wrap the onclick event inside the condition for the body class? Tried that but also not getting the alert.

    var imgContainer = document.querySelector('.img-container');

    var bodyTag = document.getElementsByTagName('body');

    var bodyClassName = bodyTag.classname;

    imgContainer.onclick = infoBox;

    function infoBox(event) {

      if (bodyTag.classList.contains("example")) {

        alert('img-container has been clicked');

      }
    }
<body class="example">
  <div class="img-container">
    <img src="https://dummyimage.com/320x120/000/fff" alt="dummy image">
    <div class="img-infobox">
      <p>This is a dummy image from https://dummyimage.com/</p>
    </div>
  </div>
</body>

Edit
From the given answers I am thinking that instead of returning an array like object and querying the DOM it would be fastest to just just document.body. no?

And this then means this question does not really have to do with

What do querySelectorAll, getElementsByClassName and other getElementsBy* methods return?

since the answer provided by the comment from https://stackoverflow.com/users/949476/dfsq uses neither of the methods from the linked answer.

Also
How can I compare the speed of using the document.querySelector vs. document.getElementsByTagName('body')[0]; vs. document.body please?

Like to give an explanation why I accepted what answer to be fair as all answers provide a working solution.

Answer
Since all answers work and document.body is fastest but also for another reason I like to post my answer here.

I am using this script from "4 novel ways to deal with sticky :hover effects on mobile devices" to handle the sticky hover problem. With this a class is added to the html tag of the site.

At first I had the click function inside the condition to check for the body or html class and only fire the click functions once the class is met, however with using this script I had to first run the function and only once it is run check if the html/body has the wanted class.

So while

  if (bodyTag.classList.contains("example")) {

    imgContainer.onclick = infoBox;

    function infoBox(event) {
        alert('img-container has been clicked and body has class "example"');    
    }

as well as

var bodyClassName = bodyTag.classname;

imgContainer.onclick = infoBox;

function infoBox(event) {

  if (bodyTag.classList.contains("example")) {

    alert('img-container has been clicked');

  }
}

works in a pure JSFiddle, it won't work with this setting since the sticky hover script sets the desired class on the element once a touch is made.

So once a click is made (I assume) it is then already too late to check for a condition outside of this touch/tap/click event and hence it won't fire.

In the end this leads to these simple lines that work together fine with the sticky hover script. The click event must run first and then check for the desired class/condition.

var imgContainer = document.querySelector('.img-container');

imgContainer.onclick = infoBox;

function infoBox(){

    if (document.documentElement.classList.contains('can-touch')) {
        alert('click on touch');
    }
}
Community
  • 1
  • 1
lowtechsun
  • 1,915
  • 5
  • 27
  • 55
  • 4
    `var bodyTag = document.getElementsByTagName('body')[0];`: https://jsfiddle.net/z6yad20p/2/ – haim770 Jan 15 '17 at 15:26
  • 1
    Or simply `var bodyTag = document.body;` – haim770 Jan 15 '17 at 15:27
  • [`.getElementsByTagName()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByTagName): "_Returns an **HTMLCollection of elements** with the given tag name._" – Andreas Jan 15 '17 at 15:27
  • So the `[0]` tells it to look for the first item in the array, but why when there is only one `body` tag? Do I need to explicitly declare that I am looking for the first `body` tag in the collection of elements even if there is only one element in the collection? – lowtechsun Jan 15 '17 at 15:31
  • Possible duplicate of [What do querySelectorAll, getElementsByClassName and other getElementsBy\* methods return?](http://stackoverflow.com/questions/10693845/what-do-queryselectorall-getelementsbyclassname-and-other-getelementsby-method) – Teemu Jan 15 '17 at 15:32
  • You can access body directly without querying DOM at all as `document.body`. – dfsq Jan 15 '17 at 15:33
  • @dfsq I shall do just that then instead of running a second query on DOM. – lowtechsun Jan 15 '17 at 15:34
  • 1
    Up to you. I would say that it's preferred. But it's good that you learned about `document.getElementsByTagName` being a collection too. – dfsq Jan 15 '17 at 15:38

2 Answers2

4

Selector used for selecting body element is not appropriate.

getElementsByTagName will give an array like object so you will have to use index to get the first element.

Read : https://developer.mozilla.org/en-US/docs/Web/API/Element/getElementsByTagName

you are already using querySelector which return the first matching element , do the same for body as well.

Read : https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector

var imgContainer = document.querySelector('.img-container');

var bodyTag = document.querySelector('body');

var bodyClassName = bodyTag.classname;

imgContainer.onclick = infoBox;

function infoBox(event) {

  if (bodyTag.classList.contains("example")) {
  
    alert('img-container has been clicked and body has class "example"');
    
  }
}
<body class="example">

  <div class="img-container">
    <img src="https://dummyimage.com/320x120/000/fff" alt="dummy image">
    <div class="img-infobox">
      <p>This is a dummy image from https://dummyimage.com/</p>
    </div>
  </div>

</body>

Performance Comparision : https://jsperf.com/body-selector-comparision

Deep
  • 9,594
  • 2
  • 21
  • 33
  • How can I compare the speed of using the `document.querySelector` vs. `document.getElementsByTagName('body')[0];` vs. `document.body` please? Like to give an explanation why I accepted what answer to be fair. – lowtechsun Jan 15 '17 at 15:43
  • best performance will be document.body because it does not involve any selector parsing. including a test run link for your code for all of these selector with your code. – Deep Jan 15 '17 at 15:53
  • Thank you. Went for your answer since you were just now also super quick to provide the performance link and you answered first. – lowtechsun Jan 15 '17 at 15:55
2

The document.getElementsByTagName returns a HTMLCollection which can be accessed as an array of objects, all you need is to select the first by using [0] after it like the following example:

var imgContainer = document.querySelector('.img-container');

    var bodyTag = document.getElementsByTagName('body')[0];

    var bodyClassName = bodyTag.classname;

    imgContainer.onclick = infoBox;

    function infoBox(event) {

      if (bodyTag.classList.contains("example")) {

        alert('img-container has been clicked');

      }
    }
<body class="example">
  <div class="img-container">
    <img src="https://dummyimage.com/320x120/000/fff" alt="dummy image">
    <div class="img-infobox">
      <p>This is a dummy image from https://dummyimage.com/</p>
    </div>
  </div>
</body>