1

I am doing a rating exercise in which I have to be able to reset my selection if I click anywhere outside of the DIV that contains the symbols, but for any reason I am unable to find the right solution.

By now, every time I execute the code, I get the message "Uncaught TypeError: Cannot read property 'classList' of null" in the line 17 of my javascript code. Does anyone know what am I doing wrong? I am out of imagination already. I copy my code below:

HTML

<!doctype html>
<html class="no-js" lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>cosanueva</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=1024, initial-scale=1">

    <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css">
    <link rel="stylesheet" href="estilos.css">
    <script src="https://use.fontawesome.com/releases/v5.0.8/js/all.js"></script>

    <script src="javascript.js"></script>

  </head>
  
  <body>
    <div class="container box">
    <div class="col-12 rating">
      <input type="radio" id="smile5" name="rating" value="5" /><label class="full" for="smile5"></label>
      <input type="radio" id="smile4" name="rating" value="4" /><label class="full" for="smile4"></label>
      <input type="radio" id="smile3" name="rating" value="3" /><label class="full" for="smile3"></label>
      <input type="radio" id="smile2" name="rating" value="2" /><label class="full" for="smile2"></label>
      <input type="radio" id="smile1" name="rating" value="1" /><label class="full" for="smile1"></label>
  </div>
  </div>

  </body>
</html>

CSS

/****** Style Smile Rating Widget *****/

.rating {
  border: none;
  float: left;
  text-align: center;
}

.rating>input {
  display: none;
}

.rating>label:before {
  margin: 5px;
  font-size: 1.25em;
  font-family: FontAwesome;
  display: inline-block;
  content: "\f118";
}

.rating>label {
  color: #ddd;
  float: right;
}


/***** CSS Magic to Highlight Smile on Hover *****/

.rating>input:checked~label,

/* show gold smile when clicked */

.rating:not(:checked)>label:hover,

/* hover current smile */

.rating:not(:checked)>label:hover~label {
  color: #FFD700;
}


/* hover previous smile in list */

.rating>input:checked+label:hover,

/* hover current smile when changing rating */

.rating>input:checked~label:hover,
.rating>label:hover~input:checked~label,

/* lighten current selection */

.rating>input:checked~label:hover~label {
  color: #FFED85;
}

JAVASCRIPT

    var box = document.querySelector(".box");

// Detect all clicks on the document
document.addEventListener("click", function(event) {
    // If user clicks inside the element, do nothing
    if (event.target.closest(".box")) return; 
    // If user clicks outside the element,
    box.classList.add(".rating>label");
});

Thank you in advance and hope you can help me! :)

Nadoto
  • 25
  • 3
  • This might help [Detect click outside div using javascript](https://stackoverflow.com/questions/36695438/detect-click-outside-div-using-javascript) – Rayees AC Sep 22 '20 at 12:19

3 Answers3

0

first thing i notice is that you dont add classNames with the dot in front not:(".rating") but ("rating"). Second thing is that ".rating>label" is not a classname but a classname with a selector. so

box.classList.add(".rating>label");

is not giving you the class "rating" it tries to add something named ".rating>label" which does not exist.

 box.classList.add("rating");

is probably what you tried to do.

For the error itself check this out: TypeError: Cannot read property 'classList' of null

Warden330
  • 999
  • 1
  • 5
  • 11
0

The browser will "work through" your code from top to bottom.

Because of this, your javascript is executed before the elements on the page are ready to be used. Because of that document.querySelector(".box") will return null and hence, you can't access the class list of null. This is what the error-message is telling you.

In this simple case it should be suffient to move the <script ...> tags to include the javascript to the end of the body like this:

<body>
    <!-- all the stuff on your page //-->

    <script src="javascript.js"></script>
</body>
lupz
  • 3,620
  • 2
  • 27
  • 43
0

Check this one :

var radios = document.querySelectorAll('input[name=rating]');

document.addEventListener("click", function(event) {
  var targ = event.target.parentElement;
  if (!(targ && targ.classList.contains('rating'))) {
    radios.forEach(e => {
      if (e.checked) {
        e.checked = false;
      }
    });
  }
});
.rating {
  border: none;
  float: left;
  text-align: center;
}

.rating>input {
  display: none;
}

.rating>label:before {
  margin: 5px;
  font-size: 1.25em;
  font-family: FontAwesome;
  display: inline-block;
  content: "\f118";
}

.rating>label {
  color: #ddd;
  float: right;
}

.rating>input:checked~label,
.rating:not(:checked)>label:hover,
.rating:not(:checked)>label:hover~label {
  color: #FFD700;
}

.rating>input:checked+label:hover,
.rating>input:checked~label:hover,
.rating>label:hover~input:checked~label,
.rating>input:checked~label:hover~label {
  color: #FFED85;
}
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css">

<script src="https://use.fontawesome.com/releases/v5.0.8/js/all.js"></script>

<div class="container box">
  <div class="col-12 rating">
    <input type="radio" id="smile5" name="rating" value="5" /><label class="full" for="smile5"></label>
    <input type="radio" id="smile4" name="rating" value="4" /><label class="full" for="smile4"></label>
    <input type="radio" id="smile3" name="rating" value="3" /><label class="full" for="smile3"></label>
    <input type="radio" id="smile2" name="rating" value="2" /><label class="full" for="smile2"></label>
    <input type="radio" id="smile1" name="rating" value="1" /><label class="full" for="smile1"></label>
  </div>
</div>
Pranav Rustagi
  • 2,604
  • 1
  • 5
  • 18