Hiding Form Elements - Clarification Needed

I am finally taking time to study JavaScript again and improve my skills in it. I have come across some code used to hide a block of elements in an html form until a checkbox is selected. The code is as follows:

var myCheckBox = document.getElementById("myCheckBox ");
var myFormElements = document.getElementById("myFormElements");

function toggleElements() {
    myCheckBox.onclick = function() {
        if (myCheckBox.checked) {
            myFormElements.style.display = "block";
        } else {
            myFormElements.style.display = "none";
        }
    };
    myFormElements.style.display = "none"; // initial state of myFormElements
}

window.onload = function() {
    toggleElements();
};

The last line in the function myFormElements.style.display = "none"; ensures that the elements are not displayed initially. But won’t it also hide the elements after the onclick event handler has finished running? In other words, won’t the elements always be hidden then?

What am I missing in this logic?

That script is dealing with display, not visibility. You’ve got to remember that visibility:hidden is NOT the same as display:none

Display none takes the element and removes it from the view completely. It doesn’t exist at all.
Visibility: hidden just makes the element invisible. All other aspects (height, width, margin, padding) all apply - you just can’t view the element itself.

Here’s a quick codepen to show the difference. Rudimentary but effective

I understand that, but in this code the onclick toggles the display of the section. Then there is a statement that sets the display to “none”, which is meant to set the initial state of the section. My question is, considering the order of the code, won’t that statement ensure that the display is always set to “none”?

Nope, because that only runs onload. Everything after that is the onClick events.

Okay, so the function toggleElements only runs once, but once it has run, the myCheckBox.onclick event is always available, even though it is inside the toggleElements function?

Correct. Technically, the toggleElements method runs once. In that method, it’s attaching an event listener to the checkbox, which sits in a “rest mode” until the checkbox has been checked/unchecked, at which time fires off the other method.

To be honest, the whole separate toggleElements event is superfluous, and it would be less confusing if everything in the toggleEvents method was just put into the onload event, though I personally would reverse the order of behavior…

var myCheckBox = document.getElementById("myCheckBox ");
var myFormElements = document.getElementById("myFormElements");

window.onload = function() {
    // all defaults first
    myFormElements.style.display = "none"; // initial state of myFormElements

    // now the event listeners....
    myCheckBox.onclick = function() {
        if (myCheckBox.checked) {
            myFormElements.style.display = "block";
        } else {
            myFormElements.style.display = "none";
        }
    };
};

The order you used makes so much more sense. Thank you for clearing up that area of confusion for me. So once the event listener is ‘activated’, it remains available for the entire time the page is loaded, and the anonymous function then can be fired multiple times.

You just removed a stumbling block for me in JavaScript. Thanks.

1 Like

This is a good exercise for me, too, @WebMachine. Are you reading a particular book or studying a course that you would recommend? I would like to try my luck at learning the basics of JS yet again.

About the code above @DaveMaxwell or @WebMachine:

On window.onload the checkbox is unchecked and the form elements are hidden.

If the checkbox is checked and the page is reloaded, the checkbox retains its checked state even though the form elements that it acts on are reset to hidden.

How does one write the JS so the checkbox resets to unchecked on page reload OR the form elements remain visible thus reflecting the state of the checkbox? Right now, there can be a “disassociation of states”. (Apologies if I’m using wrong terms.)

I am actually going through a bunch of video courses at lynda.com starting with Introducing the JavaScript Language, JavaScript: Essential Training and JavaScript for Web Designers, then on the the more specialized ones in functions, events, enhancing the DOM, Ajax (which I’ve never learned), and then I want to do all the ones here at SitePoint Premium.

Most of the first three courses are just refreshers for me because I took a couple of college courses in JavaScript back in the days of document.write (around 2010) but I am picking up some more modern techniques of doing things, and some built-in functions that are used these days that I have never heard of. I am also picking up some good advice regarding best practices.

My issue with JavaScript has always been that when I tried to write the code myself, it never came out right the first time around (almost like JavaScript didn’t like me :frowning: ) and it deteriorated into an exercise of randomly trying things until I could get it to work properly. Not the best way to do things. So it’s time to learn how to code JavaScript the right way. The funny thing is, this doesn’t happen to me in other languages.

@ronpat, in the code, I think that actually the checkbox will not retain state unless you code it to do so. (I only know how to do that with PHP, so I should stop there and let someone else help out.)

I’ll have a go at this just for fun and hopefully the JS experts can pick it apart so I learn to do it better :slight_smile:

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<script>
var root = document.documentElement;
root.className += ' hideThings';
</script>
<style>
#myFormElements {
	border: 1px solid red;
	min-height: 100px;
	width: 50%;
	margin: 1em;
	padding: .5em;
}
.hideThings #myFormElements{display:none}
</style>
</head>

<body>
<form>
  <label for="toggle">Toggle Div</label>
  <input id="myCheckBox" name="toggle" type="checkbox" value="toggle" >
  <div id="myFormElements">
    <p>This will be revealed when checkbox is clicked</p>
  </div>
</form>
<script>
(function() {

    var myCheckBox = document.getElementById("myCheckBox");
    var myFormElements = document.getElementById("myFormElements");
    myCheckBox.checked = false; // set to unchecked by default

    myCheckBox.onclick = function() {

        if (myCheckBox.checked) {
            myFormElements.style.display = "block";
        } else {
            myFormElements.style.display = "none";
        }
    };

}());
</script>
</body>
</html>

I added a class to the html element as soon as the page loads by having the script right at the top of the html. This allows the css to hide the div before the user sees the flash of content as opposed to hiding it with js. This also has the benefit that if js is disabled the element will be visible by default (you could also incorporate hiding the toggle if js is disabled by removing another class from the html).

I wouldn’t use the onload event (in case it was already being used by another script and then you would over-write it) but simply put the script at the end of the body when all content will be loaded anyway.

I’d put the script in an IIFE to avoid polluting the namespace with global variables.

Then set the checkbox to unchecked so that we always start in the hidden state. (Note that only Firefox remembers the form state on reload as this does not happen in Chrome.)

Of course I don’t really think a checkbox is the right semantic element for this because its not a form and as we are using JS a button element might be more appropriate and then there will be no state to remember.

1 Like

Thank you, @PaulOB. I’m going to try that out when I get some time later today. There is a lot to digest in your post.

Of course I don’t really think a checkbox is the right semantic element for this because its not a form and as we are using JS a button element might be more appropriate and then there will be no state to remember.

By the way, the code in the exercise that the original question was based on was a form where one section is only revealed when the checkbox is selected, so I would think a checkbox is appropriate here.

Yes in that case the checkbox approach would be fine as you could query the checkbox state serverside and then ignore any elements in that section if the element was hidden when submitted.:slight_smile:

Using a Cookie comes to mind. But except for IE 9 having some limitations I think either localStorage or sessionStorage should be adequate for a checkbox state.

http://dev-test.nemikor.com/web-storage/support-test/

Off-topic

I don’t know if the “must say you are using cookies” rules apply to storage.

With the original code, when you check the checkbox, then hit the submit button, the section hides again, and the checkbox becomes unchecked. But if you check the checkbox, don’t hit the button, but refresh the page, the section hides again but the checkbox retains the checked state. Why?

Still trying to reason through your suggestion, @PaulOB.

Paul explained…

I didn’t know that it is a Firefox idiosyncrasy.

Yes I already explained that Firefox remembers the form states in some sort of cache and pulls them back when reloaded. I believe you can turn it off with the non standard attribute autocomplete=“off” on the form control.

That’s why its better to make sure the checkbox is unchecked using js when the page loads so hat you always start form a hidden state. I don’t believe a cookie or localStorage adds any special usability in this case but of course could be utilised to remember states if needed.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.