0

I have the following function which works great in chrome, but in IE 11 doesn't.

It is designed to:

  • Take a questionGroup value determining which group of questions we want an average score for
  • Get a collections of the inputs on the page
  • Loop through them
  • If they are 'checked' then get the class name which determines the group the question is in
  • Count the number of questions in the group we're looking for
  • Get the total score for all questions in the group
  • Divide the total score by the number of questions to get the average score for the group

    function getGroupScore(questionGroup) {
        var inputs = document.getElementsByTagName("input");
        var countOfQs = 0;
        var totalGroupScore = 0;
    
        for (var element in inputs) {
    
            if (inputs[element].checked) {
    
                var theQuestionsGroup = inputs[element].className;
    
                if (theQuestionsGroup == questionGroup) {
    
                    var answer = parseInt(inputs[element].value)
    
                    totalGroupScore += answer;
    
                    countOfQs++;
    
                }
            }
        }
    
        var groupScore = totalGroupScore / countOfQs;
    
        return groupScore;
    }
    

In debugging, the loop seems to never get passed the following stage:

if (inputs[element].checked)

Even though there are input fields that are checked

example of the form I'm looping through:

<form action="">
    <table style="margin: 0 auto; border: none;" id="reschecklist">
        <tbody>
            <tr>
                <td rowspan="3" valign="top" width="400"><h3>Questions</h3></td>
                <td colspan="5" class="center"><h3>Score</h3></td>
            </tr>
            <tr>
                <td colspan="2" class="left"><strong>(not at all)</strong></td>
                <td colspan="3" align="right" class="right"><strong>(I am fully implementing this)</strong></td>
            </tr>
            <tr>
                <td>1</td>
                <td>2</td>
                <td>3</td>
                <td>4</td>
                <td>5</td>
            </tr>
            <tr>
                <td class="heading" width="400"><strong>Minimise overhead costs</strong></td>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td class="question"><p>Do you consider and identify ways to maintain machinery better and cheaper?</p></td>
                <td><input type="radio" name="q1" value="1" class="grp1" /></td>
                <td><input type="radio" name="q1" value="2" class="grp1" /></td>
                <td><input type="radio" name="q1" value="3" class="grp1" /></td>
                <td><input type="radio" name="q1" value="4" class="grp1" /></td>
                <td><input type="radio" name="q1" value="5" class="grp1" /></td>
            </tr>
            <tr>
                <td class="question"><p>Do you regularly review your overhead costs i.e. can you identify how much they cost you on a monthly, 6 monthly, annual basis?</p></td>
                <td><input type="radio" name="q2" value="1" class="grp1" /></td>
                <td><input type="radio" name="q2" value="2" class="grp1" /></td>
                <td><input type="radio" name="q2" value="3" class="grp1" /></td>
                <td><input type="radio" name="q2" value="4" class="grp1" /></td>
                <td><input type="radio" name="q2" value="5" class="grp1" /></td>
            </tr>
            <tr>
                <td class="heading" width="400"><strong>Set goals and budgets</strong></td>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td class="question"><p>Do you have a clearly set out vision and objectives for the business?</p></td>
                <td><input type="radio" name="q3" value="1" class="grp2" /></td>
                <td><input type="radio" name="q3" value="2" class="grp2" /></td>
                <td><input type="radio" name="q3" value="3" class="grp2" /></td>
                <td><input type="radio" name="q3" value="4" class="grp2" /></td>
                <td><input type="radio" name="q3" value="5" class="grp2" /></td>
            </tr>
            <tr>
                <td class="question"><p>Do you routinely (every 3-6 months), with your partner/s or your team, take a hands off view of the business and discuss objectives, performance etc?</p></td>
                <td><input type="radio" name="q4" value="1" class="grp2" /></td>
                <td><input type="radio" name="q4" value="2" class="grp2" /></td>
                <td><input type="radio" name="q4" value="3" class="grp2" /></td>
                <td><input type="radio" name="q4" value="4" class="grp2" /></td>
                <td><input type="radio" name="q4" value="5" class="grp2" /></td>
            </tr>

1 Answers1

0

for-in is not how you loop through an HTMLCollection. Use a simple for or one of the "array like" approaches in this answer (which also explains why for-in isn't the right choice here). I suspect the problem is that there are no enumerable properties in the HTMLCollection on the platform where you're seeing the problem.

So for instance:

for (var element = 0 ; element < inputs.length; ++elements) {

In modern environments, HTMLCollection (what you get back from getElementsByTagName) may have the non-standard extension making it iterable (ES2015+) and giving it a forEach. If not, you can easily add it:

if (typeof NodeList !== "undefined" &&
    NodeList.prototype &&
    !NodeList.prototype.forEach) {
    // Yes, direct assignment is fine here, no need for `Object.defineProperty`
    NodeList.prototype.forEach = Array.prototype.forEach;
}
if (typeof HTMLCollection !== "undefined" &&
    HTMLCollection.prototype &&
    !HTMLCollection.prototype.forEach) {
    // Yes, direct assignment is fine here, no need for `Object.defineProperty`
    HTMLCollection.prototype.forEach = Array.prototype.forEach;
}

That code does both HTMLCollection and NodeList (what you get from querySelectorAll). Then you can use:

inputs.forEach(function(input) {
    if (input.checked) {
        // ...
    }
});
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875