Utterly lost on SIMPLE JS

I haven’t had to do JS in about 20 years, so am utterly lost on why this event isn’t firing (goal: update mPrice, aPrice and bPrice with “monthly price”, “annual price” and brand price"… .after that i can do the backend math myself)…

<!--To change this template use Tools | Templates.
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title></title>
    
    
    
    
    <script type="text/javascript">
    var mPrice = document.getElementById("monthlyPrice");
    var aPrice = document.getElementById("annualPrice");
    var bPrice = document.getElementById("brandPrice");
        
        
    


    function calculateAll() {
            /*mPrice.value="monthly price";
            aPrice.value="annual price";
            bPrice.value="brand price";
            
            document.getElementById("mPrice").value="hello there";
        */
        
        window.alert(document.getElementById("mPrice").value);
 
        }
      
    </script>
    
    
    
    
    
    
    <style>
    input[type=checkbox]:before { 
           content:""; 
        display:inline-block; 
        width:12px; 
        height:12px; 
        background:red; 
    }
        
input[type=checkbox]:checked:before { 
    background:green; 
}
    </style>
    
</head>
<body>
    <h1>SoCast Price Calculator</h1>
    
    <form id="myForm">
        
        <h3>Module Costs</h3>
        <label for="modc1">CMS</label><input type="label" id="modc1" /><br />
        <label for="modc2">Social</label><input type="label" id="modc2" /><br />
        <label for="modc3">Email</label><input type="label" id="modc3" /><br />
        <label for="modc4">Mobile App</label><input type="label" id="modc4" /><br />
        <label for="modc5">Promotions</label><input type="label" id="modc5" /><br />
        <label for="modc6">Single Sign-On</label><input type="label" id="modc6" /><br />
        
        
        <h3>Support Costs</h3>
        <label for="supc1">Basic Support</label><input type="label" id="supc1" /><br />
        <label for="supc2">Premium Support</label><input type="label" id="supc2" /><br />
        <label for="supc3">Enterprise Support</label><input type="label" id="supc3" /><br />
        
        <h3>Add-On Costs</h3>
        <label for="addc1">Setup & Transfer</label><input type="label" id="addc1" /><br />
        <label for="addc2">Coaching</label><input type="label" id="addc2" /><br />
        <label for="addc3">Basic Training</label><input type="label" id="addc3" /><br />
        <label for="addc4">Advanced Training</label><input type="label" id="addc4" /><br />
        
        <h3>Discounts</h3>
        <label for="discc1">2 Modules</label><input type="label" id="discc1" /><br />
        <label for="discc2">3 Modules</label><input type="label" id="discc2" /><br />
        <label for="discc3">4 Modules</label><input type="label" id="discc3" /><br />
        <label for="discc4">5 Modules</label><input type="label" id="discc4" /><br />
        <label for="discc5">6 Modules</label><input type="label" id="discc5" /><br />
        <label for="discc6">5 Brands</label><input type="label" id="discc6" /><br />
        <label for="discc7">10 Brands</label><input type="label" id="discc7" /><br />
        <label for="discc8">25 Brands</label><input type="label" id="discc8" /><br />
        <label for="discc9">50 Brands</label><input type="label" id="discc9" /><br />
        <label for="discc10">100 Brands</label><input type="label" id="discc10" /><br />
        <label for="discc11">2 Year Commitment</label><input type="label" id="discc11" /><br />
        <label for="discc12">3 Year Commitment</label><input type="label" id="discc12" /><br />
        <label for="discc13">5 Year Commitment</label><input type="label" id="discc13" /><br />
        
        
          <h2>Brands</h2>
        <label for="brand1">How Many Brands</label><input type="label" id="brand1" /><br />
        
        
        
        <h2>Modules</h2>
        <input type="checkbox" id="mod1" /><label for="mod1">CMS</label><br/>
    <input type="checkbox" id="mod2" /> <label for="mod2">Social</label><br/>
      <input type="checkbox" id="mod3" /> <label for="mod3">Email</label><br/>
         <input type="checkbox" id="mod4" /> <label for="mod4">Mobile App</label><br/>
         <input type="checkbox" id="mod5" /> <label for="mod5">Promotions</label><br/>
         <input type="checkbox" id="mod6" /> <label for="mod6">Single Sign-On</label><br/>
        
        
        
        <h2>Commitment</h2>
      <input type="checkbox" id="commit1" /><label for="commit1">1 Year</label><br/>
    <input type="checkbox" id="commit2" /> <label for="commit2">2 Years</label><br/>
      <input type="checkbox" id="commit3" /> <label for="commit3">3 Years</label><br/>
       <input type="checkbox" id="commit4" /> <label for="commit4">4 Years</label><br/>
        <input type="checkbox" id="commit5" /> <label for="commit5">5 Years</label><br/>
        
        
        <input type="button" id="calculate" value="Calculate All" /><br /><br />
        
        <h2>Quote</h2>
        
        <label for="monthlyPrice">Monthly Price</label><input type="label" id="monthlyPrice" value="1" /><br />
        <label for="annualPrice">Annual Price</label><input type="label" id="annualPrice" value="2" /><br />
        <label for="brandPrice">Price Per Brand Per Month</label><input type="label" id="brandPrice" value="3" /><br />
        
        
        
        
    </form>


    
    
        <script type="text/javascript">
 
            document.getElementById("calculate").onclick = function() {
                calculateAll();
            }
    </script>
    
    
</body>
</html>

The common practice these days is to put all of the JS at the bottom of the document. Otherwise, the variables like mPrice are empty when the page loads, because the script looks for the corresponding elements but they haven’t loaded yet.

<script type="text/javascript">
function calculateAll() {
    var mPrice = document.getElementById("monthlyPrice");
    var aPrice = document.getElementById("annualPrice");
    var bPrice = document.getElementById("brandPrice");
    mPrice.value="monthly price";
    aPrice.value="annual price";
    bPrice.value="brand price";
}
document.getElementById("calculate").onclick = function() {
    calculateAll();
}
</script>
    
[COLOR="#FF0000"]</body>[/COLOR]

Yes, when I first got away from inline style and script many years ago it “made sense” to put them in the head, then to put them in referenced files.
Putting script at the end just didn’t “feel” right. So I put script inside functions and used “onload” (or in jQuery-speak “ready”) to call them.

But in time the pragmatist in me got me used to putting script that worked with the DOM at the end after the DOM was there to be worked with.

Let’s do a little bit of a review of the code, to see how things have changed over time.

Doctype

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

HTML 4.01 is perfectly good, but being transitional means that you expect to use HTML 3 coding techniques as well, so that back in 1997 you could still use HTML 3 code with the HTML 4 doctype, while you were in the process of updating your code.

Using HTML 4 strict is much preferred, for then you can be sure that your HTML code is up to standard.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

Although these days, HTML 5 is the preferred standard to use, which allows the HTML 4.01 standard too.

<DOCTYPE html>

Title

The page has an empty title, which is used when someone bookmarks the page, and is also shown in the titlebar/tab of the browser window.

<title></title>

Script in head

The script is in the head of the page, which is a practice from the days of HTML 3 as well. HTML 4 allowed the script to also be in the body of the page.

When the script is in the head, it cannot interact with the rest of the page. Scripts (regardless of being in head or body) can only interact with that which is above them. Anything below the script doesn’t actually exist when the script is run. When head-based scripts this usually meant using a body onload event to call a function of the script, to get things started.

What with the web standards model and the practice of separating the HTML/CSS/JavaScript from each other, we’ve learned that keeping all of the scripting in one place makes the most sense. Also, with the scripting happening at the end of the body, the rest of the HTML document is accessible above it, so no onload event needs to take place to get things started.

Checkboxes

When first looking at the page I had absolutely no idea that you could interact with the red/green boxes beside some of the content. It’s an interesting idea to colour-code whether they’ve been selected, but removing the visual aspect checkboxes can break the user interface if people are not used to it. Red is often reserved on the user interface for indicating something that is bad or needs fixing.

Also, checkboxes are not useful when only one selection is allowed, such as for the Commitment section. An option group there to ensure that only one option is chosen is the best way to work things there. Jakob Nielsen would certainly have words with you, in regard to the usability of Checkboxes vs Radio Buttons.

I’m not sure what you’re wanting to convey here, but it could do with some further refinement before you come to a successful end to things.

Form content

With HTML 4 the content of forms needs to be contained within block-level elements, which commonly means that it’s contained within divs, paragraphs, or fieldset. The labels should be within paragraph tags. Line breaks are also a huge no-no, and are normally restricted to formatting only poems or addresses where line breaks are mandatory there.

Also, the type attribute should be text, instead of label.

<p><label for="modc1">CMS</label><input type="text" id="modc1" /></p>

By giving the form paragraphs a zero margin, you can achieve the same look as when line breaks are used:


form p {
    margin: 0;
}

Form fields

None of your form fields will be submitted, because they don’t have a name attribute. When using labels it’s best practice to use the id attribute for the label, and to not use the id for anything else. The only access to form fields should be via the form.elements collection. JavaScript has the form.elements collection that provides a nice interface with which to work with the form fields.

<p><label for="modc1">CMS</label><input type="label" name="modc1" id="modc1" /></p>

Self-closing tags

It’s also odd that you are using HTML 4 but have XHTML self-closing tags in there. If you don’t want to remove the self-closing tags, you really should update the doctype to be more than just HTML 4. Using the HTML 5 doctype is a good way to allow you to use whichever style you prefer.

The crux of the problem

After placing the script at the end of the body, just before the other script, we finally get to learn about the problem that is happening. You are using document.getElementById with a string value of “mPrice”. That is the name of the local JavaScript variable that you are using, and is not the name of the unique identifier that’s on the field.

The best way to resolve this problem is to just use getElementById to gain a reference to the form, and from then on to use the form.elements collection to retrieve fields based on their name attribute instead.

Here’s the updated code from which you can make further progress on. I hope that this has helped you in some way.


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <title>SoCast Price Calculator</title>

    <style>
    input[type=checkbox]:before {
           content:"";
        display:inline-block;
        width:12px;
        height:12px;
        background:red;
    }

input[type=checkbox]:checked:before {
    background:green;
}
form p {
    margin: 0;
}
    </style>
</head>
<body>
    <h1>SoCast Price Calculator</h1>

    <form id="myForm">

        <h3>Module Costs</h3>
        <p><label for="modc1">CMS</label><input type="text" name="modc1" id="modc1" /></p>
        <p><label for="modc2">Social</label><input type="text" name="modc2" id="modc2" /></p>
        <p><label for="modc3">Email</label><input type="text" name="modc3" id="modc3" /></p>
        <p><label for="modc4">Mobile App</label><input type="text" name="modc4" id="modc4" /></p>
        <p><label for="modc5">Promotions</label><input type="text" name="modc5" id="modc5" /></p>
        <p><label for="modc6">Single Sign-On</label><input type="text" name="modc6" id="modc6" /></p>


        <h3>Support Costs</h3>
        <p><label for="supc1">Basic Support</label><input type="text" name="supc1" id="supc1" /></p>
        <p><label for="supc2">Premium Support</label><input type="text" name="supc2" id="supc2" /></p>
        <p><label for="supc3">Enterprise Support</label><input type="text" name="supc3" id="supc3" /></p>

        <h3>Add-On Costs</h3>
        <p><label for="addc1">Setup & Transfer</label><input type="text" name="addc1" id="addc1" /></p>
        <p><label for="addc2">Coaching</label><input type="text" name="addc2" id="addc2" /></p>
        <p><label for="addc3">Basic Training</label><input type="text" name="addc3" id="addc3" /></p>
        <p><label for="addc4">Advanced Training</label><input type="text" name="addc4" id="addc4" /></p>

        <h3>Discounts</h3>
        <p><label for="discc1">2 Modules</label><input type="text" name="discc1" id="discc1" /></p>
        <p><label for="discc2">3 Modules</label><input type="text" name="discc2" id="discc2" /></p>
        <p><label for="discc3">4 Modules</label><input type="text" name="discc3" id="discc3" /></p>
        <p><label for="discc4">5 Modules</label><input type="text" name="discc4" id="discc4" /></p>
        <p><label for="discc5">6 Modules</label><input type="text" name="discc5" id="discc5" /></p>
        <p><label for="discc6">5 Brands</label><input type="text" name="discc6" id="discc6" /></p>
        <p><label for="discc7">10 Brands</label><input type="text" name="discc7" id="discc7" /></p>
        <p><label for="discc8">25 Brands</label><input type="text" name="discc8" id="discc8" /></p>
        <p><label for="discc9">50 Brands</label><input type="text" name="discc9" id="discc9" /></p>
        <p><label for="discc10">100 Brands</label><input type="text" name="discc10" id="discc10" /></p>
        <p><label for="discc11">2 Year Commitment</label><input type="text" name="discc11" id="discc11" /></p>
        <p><label for="discc12">3 Year Commitment</label><input type="text" name="discc12" id="discc12" /></p>
        <p><label for="discc13">5 Year Commitment</label><input type="text" name="discc13" id="discc13" /></p>


        <h2>Brands</h2>
        <p><label for="brand1">How Many Brands</label><input type="text" name="brand1" id="brand1" /></p>



        <h2>Modules</h2>
        <p><input type="checkbox" name="mod1" id="mod1" /> <label for="mod1">CMS</label></p>
        <p><input type="checkbox" name="mod2" id="mod2" /> <label for="mod2">Social</label></p>
        <p><input type="checkbox" name="mod3" id="mod3" /> <label for="mod3">Email</label></p>
        <p><input type="checkbox" name="mod4" id="mod4" /> <label for="mod4">Mobile App</label></p>
        <p><input type="checkbox" name="mod5" id="mod5" /> <label for="mod5">Promotions</label></p>
        <p><input type="checkbox" name="mod6" id="mod6" /> <label for="mod6">Single Sign-On</label></p>



        <h2>Commitment</h2>
        <p><input type="radio" name="commit" id="commit1" value="1" /> <label for="commit1">1 Year</label></p>
        <p><input type="radio" name="commit" id="commit2" value="2" /> <label for="commit2">2 Years</label></p>
        <p><input type="radio" name="commit" id="commit3" value="3" /> <label for="commit3">3 Years</label></p>
        <p><input type="radio" name="commit" id="commit4" value="4" /> <label for="commit4">4 Years</label></p>
        <p><input type="radio" name="commit" id="commit5" value="5" checked="checked" /> <label for="commit5">5 Years</label></p>


        <p><input type="button" id="calculate" value="Calculate All" /></p>

        <h2>Quote</h2>

        <p><label for="monthlyPrice">Monthly Price</label><input type="text" name="monthlyPrice" id="monthlyPrice" value="1" /></p>
        <p><label for="annualPrice">Annual Price</label><input type="text" name="annualPrice" id="annualPrice" value="2" /></p>
        <p><label for="brandPrice">Price Per Brand Per Month</label><input type="text" name="brandPrice" id="brandPrice" value="3" /></p>
    </form>

    <script type="text/javascript">
    var form = document.getElementById('myForm');

    function calculateAll() {
        form.elements.monthlyPrice.value="monthly price";
        form.elements.annualPrice.value="annual price";
        form.elements.brandPrice.value="brand price";

        form.elements.monthlyPrice.value="hello there";

        window.alert(form.elements.monthlyPrice.value);

        }

        document.getElementById("calculate").onclick = function() {
            calculateAll();
        }
    </script>
</body>
</html>

Huge thanks all, especially Paul for the rewrite. All that feedback DEF makes sense. As I said, haven’t written code in so many years hah. As far as the checkboxes, they’re gonna be big images eventually. This is an internal tool for our sales team, so the simpler the better!