'JavaScript form script works Chrome but nowhere else

2nd update 9/6/2015

So here's what I came up with for a solution—it's certainly much shorter, and works in all my Mac browsers so I'm assuming it works elsewhere too. Is there a way to condense it further or should I leave it at this?

var myForm = document.form1;
var radioNames = [myForm.proSpeed, myForm.ram, myForm.storage, myForm.graphics, myForm.cursorControl];
var lastPrice = [0, 0, 0, 0, 0];
var total = 2299;
var result = document.getElementById('result');
result.innerHTML = "$" + total + ".00";

function getLastPrice(radios, lastPriceIndex) {    
    for (var index = 0; index < radios.length; index++) {
        if (radios[index].checked) {
            var price = parseInt(radios[index].value);
            total = total + lastPrice[lastPriceIndex] + price;
            result.innerHTML = "$" + total + ".00";
            lastPrice[lastPriceIndex] = -price;
        }
    }    
}

function getProPrice() {
    getLastPrice(myForm.proSpeed, 0);
}
function getRamPrice() {
    getLastPrice(myForm.ram, 1);
}
function getStoPrice() {
    getLastPrice(myForm.storage, 2);
}
function getGraPrice() {
    getLastPrice(myForm.graphics, 3);
}
function getCurPrice() {
    getLastPrice(myForm.cursorControl, 4);
}

var priceFunctions = [getProPrice, getRamPrice, getStoPrice, getGraPrice, getCurPrice];

function addRadioListeners(radios, priceFunction) {
    for (var index = 0; index < radios.length; index++) {
        radios[index].addEventListener("change", priceFunction);
    }
}

for (var index = 0; index < 5; index++) {
    addRadioListeners(radioNames[index], priceFunctions[index]);
}

UPDATE 9/5/2015

@Barmar thanks again for all your help. I'm now combining the addPrice functions:

function addPrice(price, radios) {
    for (var index = 0; index < radios.length; index++) {
        if (radios[index].checked) {
            total = total - price + parseInt(radios[index].value);
            price = parseInt(radios[index].value);
            result.innerHTML = "$" + total + ".00";
            break;
        }
    }
}

proPrice = addPrice(proPrice, myForm.proSpeed);

Just not sure what to do next to remove the other functions and keep the form working. In other words where does proPrice go and what do I put in the change eventListener now that addProPrice no longer exists? proPrice comes back as undefined.


Original Post

I'm working on a JavaScript exercise that had me create a build-your-own-computer store page, so I decided to just try to mimic a page from the Apple Store. Here's the page I'm trying to copy:

Retina 5k iMac

And here's my (very) bare-bones version: mock-up of iMac store page

My version works in Chrome, but not in Firefox or Safari. I have no idea what the problem is. Any thoughts?

(Below is the full code in case you don't want to follow the link)

HTML:

<!DOCTYPE html>

<html lang="en">
<head>
    <title>Apple Store Sim</title>
</head>

<body>

<form action="" name="form1" id="form1">
    <h1>iMac with Retina 5K display</h1>
    <p>1. Choose Processor</p>
    <p>
        <input type="radio" name="proSpeed" checked="checked" value="0" />
        <label>3.5GHz Quad-core Intel Core i5, Turbo Boost up to 3.9GHz</label><br />
        <input type="radio" name="proSpeed" value="250" />
        <label>4.0GHz Quad-core Intel Core i7, Turbo Boost up to 4.4GHz</label>
    </p>
    <p>2. Choose Memory</p>
    <p>
        <input type="radio" name="ram" checked="checked" value="0" />
        <label>8GB 1600MHz DDR3 SDRAM - 2x4GB</label><br />
        <input type="radio" name="ram" value="200" />
        <label>16GB 1600MHz DDR3 SDRAM - 2x8GB</label><br />
        <input type="radio" name="ram" value="600" />
        <label>32GB 1600MHz DDR3 SDRAM - 4x8GB</label>
    </p>
    <p>3. Choose Storage</p>
    <p>
        <input type="radio" name="storage" checked="checked" value="0" />
        <label>1TB Fusion Drive</label><br />
        <input type="radio" name="storage" value="150" />
        <label>3TB Fusion Drive</label><br />
        <input type="radio" name="storage" value="0" />
        <label>256GB Flash Storage</label><br />
        <input type="radio" name="storage" value="300" />
        <label>512GB Flash Storage</label><br />
        <input type="radio" name="storage" value="800" />
        <label>1TB Flash Storage</label>
    </p>
    <p>4. Choose Graphics</p>
    <p>
        <input type="radio" name="graphics" checked="checked" value="0" />
        <label>AMD Radeon R9 M290X 2GB GDDR5</label><br />
        <input type="radio" name="graphics" value="250" />
        <label>AMD Radeon R9 M295X 4GB GDDR5</label>
    </p>
    <p>5. Choose Mouse and Magic Trackpad</p>
    <p>
        <input type="radio" name="cursorControl" checked="checked" value="0" />
        <label>Apple Magic Mouse</label><br />
        <input type="radio" name="cursorControl" value="0" />
        <label>Magic Trackpad</label><br />
        <input type="radio" name="cursorControl" value="0" />
        <label>Apple Mouse</label><br />
        <input type="radio" name="cursorControl" value="69" />
        <label>Apple Magic Mouse + Magic Trackpad</label><br />
    </p>
    <p>6. Choose Apple Keyboard and Documentation</p>
    <p>
        <select name="keyboard" size="1">
            <option value="0" selected="selected">Apple Wireless Keyboard (English) &amp; User's Guide</option>
            <option value="0">Apple Wireless Keyboard (Arabic) &amp; User's Guide</option>
            <option value="0">Apple Wireless Keyboard (British) &amp; User's Guide</option>
        </select>
    </p>
</form>
<div id="result"></div>
<script src="appleStoreSim.js"></script>
</body>
</html>

Javascript:

var myForm = document.form1;
var proPrice = 0;
var ramPrice = 0;
var stoPrice = 0;
var graPrice = 0;
var curPrice = 0;
var total = 2299;
var result = document.getElementById('result');
result.innerHTML = "$" + total + ".00";

function addProPrice(radio) {
    var radios = myForm.proSpeed;
    
    for (var index = 0; index < radios.length; index++) { 
        if (radios[index].checked) {
            total = total - proPrice + parseInt(radios[index].value);
            result.innerHTML = "$" + total + ".00";
            addProListener();
        }
    }    
}

function addProListener(radio) {
    var radios = myForm.proSpeed;

    for (var index = 0; index < radios.length; index++) {
        if (radios[index].checked) {
            radios[index].removeEventListener("click", addProPrice);
            proPrice = radios[index].value;
        } else {
            radios[index].addEventListener("click", addProPrice)
        }
    }
}

for (var index = 0; index < myForm.proSpeed.length; index++) { 
    myForm.proSpeed[index].addEventListener("focus", addProListener);
}

function addMemPrice(radio) {
    var radios = myForm.ram;
    
    for (var index = 0; index < radios.length; index++) { 
        if (radios[index].checked) {
            total = total - ramPrice + parseInt(radios[index].value);
            result.innerHTML = "$" + total + ".00";
            addMemListener();
        }
    }
}

function addMemListener(radio) {
    var radios = myForm.ram;
    
    for (var index = 0; index < radios.length; index++) {
        if (radios[index].checked) {
            radios[index].removeEventListener("click", addMemPrice);
            ramPrice = radios[index].value;
        } else {
            radios[index].addEventListener("click", addMemPrice)
        }
    }
}

for (var index = 0; index < myForm.ram.length; index++) { 
    myForm.ram[index].addEventListener("focus", addMemListener);
}

function addStoPrice(radio) {
    var radios = myForm.storage;
    
    for (var index = 0; index < radios.length; index++) { 
        if (radios[index].checked) {
            total = total - stoPrice + parseInt(radios[index].value);
            result.innerHTML = "$" + total + ".00";
            addStoListener();
        }
    }
}

function addStoListener(radio) {
    var radios = myForm.storage;
    
    for (var index = 0; index < radios.length; index++) {
        if (radios[index].checked) {
            radios[index].removeEventListener("click", addStoPrice);
            stoPrice = radios[index].value;
        } else {
            radios[index].addEventListener("click", addStoPrice)
        }
    }
}

for (var index = 0; index < myForm.storage.length; index++) { 
    myForm.storage[index].addEventListener("focus", addStoListener);
}

function addGraPrice(radio) {
    var radios = myForm.graphics;
    
    for (var index = 0; index < radios.length; index++) { 
        if (radios[index].checked) {
            total = total - graPrice + parseInt(radios[index].value);
            result.innerHTML = "$" + total + ".00";
            addGraListener();
        }
    }
}

function addGraListener(radio) {
    var radios = myForm.graphics;
    
    for (var index = 0; index < radios.length; index++) {
        if (radios[index].checked) {
            radios[index].removeEventListener("click", addGraPrice);
            graPrice = radios[index].value;
        } else {
            radios[index].addEventListener("click", addGraPrice)
        }
    }
}

for (var index = 0; index < myForm.graphics.length; index++) { 
    myForm.graphics[index].addEventListener("focus", addGraListener);
}

function addCurPrice(radio) {
    var radios = myForm.cursorControl;
    
    for (var index = 0; index < radios.length; index++) { 
        if (radios[index].checked) {
            total = total - curPrice + parseInt(radios[index].value);
            result.innerHTML = "$" + total + ".00";
            addCurListener();
        }
    }
}

function addCurListener(radio) {
    var radios = myForm.cursorControl;
    
    for (var index = 0; index < radios.length; index++) {
        if (radios[index].checked) {
            radios[index].removeEventListener("click", addCurPrice);
            curPrice = radios[index].value;
        } else {
            radios[index].addEventListener("click", addCurPrice)
        }
    }
}

for (var index = 0; index < myForm.cursorControl.length; index++) { 
    myForm.cursorControl[index].addEventListener("focus", addCurListener);
}


Solution 1:[1]

Firefox on the Mac doesn't trigger the focus event when you click on a radio button. I haven't researched whether this is a standard violation, but there's a simpler way to do what you're doing. Instead of using the focus event to add a click handler, just use the change event. This will be triggered whenever you click on a radio button that wasn't already checked. This can be bound directly to the addXXXPrice functions.

BTW, all your addXXXPrice functions are declared with a radio parameter that they never use. The actual argument to an event handler is an event object, not the radio button; the target of the event will be in this.

And all those addXXXPrice functions are identical, except for the set of buttons they loop over and the xxxPrice variable they update. I suggest you pull that out into a single function that takes those things as parameters, so you can do:

proPrice = addPrice(proPrice, myForm.proSpeed);

Here's the revised version of your code:

var myForm = document.form1;
var proPrice = 0;
var ramPrice = 0;
var stoPrice = 0;
var graPrice = 0;
var curPrice = 0;
var total = 2299;
var result = document.getElementById('result');
result.innerHTML = "$" + total + ".00";
//total = parseFloat(total).toFixed(2);

console.log(result);

function addProPrice(radio) {
  var radios = myForm.proSpeed;

  for (var index = 0; index < radios.length; index++) {
    if (radios[index].checked) {
      total = total - proPrice + parseInt(radios[index].value);
      proPrice = parseInt(radios[index].value);
      result.innerHTML = "$" + total + ".00";
      break;
    }
  }
}

for (var index = 0; index < myForm.proSpeed.length; index++) {
  myForm.proSpeed[index].addEventListener("change", addProPrice);
}

function addMemPrice(radio) {
  var radios = myForm.ram;

  for (var index = 0; index < radios.length; index++) {
    if (radios[index].checked) {
      total = total - ramPrice + parseInt(radios[index].value);
      ramPrice = parseInt(radios[index].value);
      result.innerHTML = "$" + total + ".00";
      break;
    }
  }
}

for (var index = 0; index < myForm.ram.length; index++) {
  myForm.ram[index].addEventListener("change", addMemPrice);
}

function addStoPrice(radio) {
  var radios = myForm.storage;

  for (var index = 0; index < radios.length; index++) {
    if (radios[index].checked) {
      total = total - stoPrice + parseInt(radios[index].value);
      stoPrice = parseInt(radios[index].value);
      result.innerHTML = "$" + total + ".00";
      break;
    }
  }
}

for (var index = 0; index < myForm.storage.length; index++) {
  myForm.storage[index].addEventListener("change", addStoPrice);
}

function addGraPrice(radio) {
  var radios = myForm.graphics;

  for (var index = 0; index < radios.length; index++) {
    if (radios[index].checked) {
      total = total - graPrice + parseInt(radios[index].value);
      graPrice = parseInt(radios[index].value);
      result.innerHTML = "$" + total + ".00";
      break;
    }
  }
}

for (var index = 0; index < myForm.graphics.length; index++) {
  myForm.graphics[index].addEventListener("change", addGraPrice);
}

function addCurPrice(radio) {
  var radios = myForm.cursorControl;

  for (var index = 0; index < radios.length; index++) {
    if (radios[index].checked) {
      total = total - curPrice + parseInt(radios[index].value);
      curPrice = parseInt(radios[index].value);
      result.innerHTML = "$" + total + ".00";
      break;
    }
  }
}

for (var index = 0; index < myForm.cursorControl.length; index++) {
  myForm.cursorControl[index].addEventListener("change", addCurPrice);
}
<form action="" name="form1" id="form1">
  <h1>iMac with Retina 5K display</h1>
  <p>1. Choose Processor</p>
  <p>
    <input type="radio" name="proSpeed" checked="checked" value="0" />
    <label>3.5GHz Quad-core Intel Core i5, Turbo Boost up to 3.9GHz</label>
    <br />
    <input type="radio" name="proSpeed" value="250" />
    <label>4.0GHz Quad-core Intel Core i7, Turbo Boost up to 4.4GHz</label>
  </p>
  <p>2. Choose Memory</p>
  <p>
    <input type="radio" name="ram" checked="checked" value="0" />
    <label>8GB 1600MHz DDR3 SDRAM - 2x4GB</label>
    <br />
    <input type="radio" name="ram" value="200" />
    <label>16GB 1600MHz DDR3 SDRAM - 2x8GB</label>
    <br />
    <input type="radio" name="ram" value="600" />
    <label>32GB 1600MHz DDR3 SDRAM - 4x8GB</label>
  </p>
  <p>3. Choose Storage</p>
  <p>
    <input type="radio" name="storage" checked="checked" value="0" />
    <label>1TB Fusion Drive</label>
    <br />
    <input type="radio" name="storage" value="150" />
    <label>3TB Fusion Drive</label>
    <br />
    <input type="radio" name="storage" value="0" />
    <label>256GB Flash Storage</label>
    <br />
    <input type="radio" name="storage" value="300" />
    <label>512GB Flash Storage</label>
    <br />
    <input type="radio" name="storage" value="800" />
    <label>1TB Flash Storage</label>
  </p>
  <p>4. Choose Graphics</p>
  <p>
    <input type="radio" name="graphics" checked="checked" value="0" />
    <label>AMD Radeon R9 M290X 2GB GDDR5</label>
    <br />
    <input type="radio" name="graphics" value="250" />
    <label>AMD Radeon R9 M295X 4GB GDDR5</label>
  </p>
  <p>5. Choose Mouse and Magic Trackpad</p>
  <p>
    <input type="radio" name="cursorControl" checked="checked" value="0" />
    <label>Apple Magic Mouse</label>
    <br />
    <input type="radio" name="cursorControl" value="0" />
    <label>Magic Trackpad</label>
    <br />
    <input type="radio" name="cursorControl" value="0" />
    <label>Apple Mouse</label>
    <br />
    <input type="radio" name="cursorControl" value="69" />
    <label>Apple Magic Mouse + Magic Trackpad</label>
    <br />
  </p>
  <p>6. Choose Apple Keyboard and Documentation</p>
  <p>
    <select name="keyboard" size="1">
      <option value="0" selected="selected">Apple Wireless Keyboard (English) &amp; User's Guide</option>
      <option value="0">Apple Wireless Keyboard (Arabic) &amp; User's Guide</option>
      <option value="0">Apple Wireless Keyboard (British) &amp; User's Guide</option>
    </select>
  </p>
</form>
<div id="result"></div>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1