1

I am learning how to do form validation on various types of elements and want to do this in only Javascript. I have some checkboxes here and a Javascript function that checks if the checkboxes has at least one option selected on form submission. Basically the checkboxes should show up red if no option is selected. But I get the error:

Uncaught TypeError: Cannot set property 'borderColor' of undefined

function validate() {
  var ok = true;
  var yes = document.getElementById("yes").checked
  var no = document.getElementById("no").checked;

  if (!yes && !no) {
    document.getElementsByClassName(".btn-group").style.borderColor = "red";
  }

  return ok;
}
<div data-toggle="buttons" class="btn-group">
  <label class="btn active">
    <input id = "yes" type="checkbox" name="box" value="yes" />
    </i>Yes
  </label>

  <label class="btn active">
    <input id = "no" type="checkbox" name="box" value="no" />No
  </label>
</div>

11
  • I commend you for attempting this in pure JS! Commented Aug 9, 2016 at 15:53
  • 1
    Consider using a radio instead of a checkbox. Commented Aug 9, 2016 at 15:54
  • document.getElementById get elements by its id attribute, not its value. So try <input type="checkbox" name="box" value="no" id="yes" />, or alternatively, try document.querySelector('input[value="yes"]')Also, theres an <i> tag on the loose. Commented Aug 9, 2016 at 15:54
  • I the id originally! I forgot to write them here before Commented Aug 9, 2016 at 15:56
  • 1
    DanielShillshock said it was pure javascript. A couple more notes: getElementsByClassName return an list of elements, so to select the first result you need to use getElementsByClassName(...)[0]. Commented Aug 9, 2016 at 15:58

3 Answers 3

4

There are a few problems there:

  1. If you use getElementsByClassName you should use the classname without the dot.
  2. The style property is for the element (while getElementsByClassName returns a list of the elements).
  3. If you only set the color of the border (and not the style and the width) there will be no border.

Here is the correction:

function validate() {
  var ok = true;
  var yes = document.getElementById("yes").checked
  var no = document.getElementById("no").checked;

  if (!yes && !no) {
    ok = false;
    document.getElementsByClassName("btn-group")[0].style.border = '1px solid red';
  } else {
    document.getElementsByClassName("btn-group")[0].style.border = '';
  }
  return ok;
}
<div data-toggle="buttons" class="btn-group">
  <label class="btn active">
    <input id = "yes" type="checkbox" name="box" value="yes" />
    Yes
  </label>

  <label class="btn active">
    <input id = "no" type="checkbox" name="box" value="no" />No
  </label>
</div>

<button onclick="validate()">Validate</button>

Sign up to request clarification or add additional context in comments.

Comments

1

getElementsByClassName() Returns a collection of elements, so you need to iterate over the result to make sure you apply the style change to each element.

Furthermore, you need to use the element.setAttribute() method to change the style like so:

element.setAttribute("style","border-color: red");

Combining those two things should get you the result you want.

Edit: you don't have to use setAttribute() if you don't want to, as Neal pointed out. The important thing to take away is that you need to iterate over your collection.

Edit 2: Looking at your code again, I noticed that when you call document.getElementsByClassName(".btn-group").style.borderColor = "red";, you're not retrieving the check boxes, you're getting a collection of divs of class btn-group, so you're actually attempting to set the border color of the div to be red, not the check boxes. You're also always returning true unconditionally at the end of validate().

If you're only checking these 2 check boxes, you can just simply use the id's to change them:

function validate() {
  var ok = true;
  var yes = document.getElementById("yes").checked
  var no = document.getElementById("no").checked;

  if (!yes && !no) {
    document.getElementById("yes").setAttribute("style","border-color: red");
    document.getElementById("no").setAttribute("style","border-color: red");
    // no checkbox selected, validation should fail and return false
    return !ok;
  } else {
    // checkbox selected, validation should pass and return true
    return ok;
  }
}

3 Comments

No need for setAttribute.
The first part of your answer is correct though :-)
I've been doing java for too long and am set in the ways of using mutators, but yes, you're right.
0

You should add or remove a class to the button group in order to hide show the border. Just add or remove the class when validation changes.

Also, you need to either iterate over all the button group classes or choose one.

Note: I used the class methods from You Might Not Need jQuery.

function validate() {
  var btnGroups = document.getElementsByClassName("btn-group");

  for (var i = 0; i < btnGroups.length; i++) {
    var btnGroup = btnGroups[i];
    var yes = document.getElementById("yes")['checked'] == true;
    var no = document.getElementById("no")['checked'] == true;

    if (!yes && !no) {
      if (!hasClass(btnGroup, 'invalid')) addClass(btnGroup, 'invalid');
      return false;
    } else {
      if (hasClass(btnGroup, 'invalid')) removeClass(btnGroup, 'invalid');
    }
  }

  return true;
}

function hasClass(el, className) {
  if (el.classList) return el.classList.contains(className);
  else return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
}

function addClass(el, className) {
  if (el.classList) el.classList.add(className);
  else el.className += ' ' + className;
}

function removeClass(el, className) {
  if (el.classList) el.classList.remove(className);
  else el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
}
.btn-group.invalid {
  border : thin solid red;
}
<div data-toggle="buttons" class="btn-group">
  <label class="btn active">
    <input type="checkbox" id="yes" name="box" value="yes" onchange="validate()" />Yes
  </label>

  <label class="btn active">
    <input type="checkbox" id="no" name="box" value="no" onchange="validate()" />No
  </label>
</div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.