JS question from a JS noob

I am an SQL/PHP guy. I know my way around html, but JS is not what I do.

That being said, I’m creating a data entry form, and I need to know how to do something.

I will attach a code snippet at the end of the post.

basically, the user inputs a number, and a radio is checked stating if it falls within a range, plus some color changes. There can be any number of these input questions. (or, in some cases, the radio is directly selected). In any event, I need the “submit” button to change color AND change the word on it based on if ANY ONE of the radio inputs are “fail”.

Here is the snippet.

<script>
function PassFail(lownum,hinum,userin,pfy,pfn){
var UserInput = document.getElementById(userin).value;
if (UserInput >= lownum && UserInput <= hinum){
document.getElementById(pfy).checked = true;
document.getElementById(pfn).checked = false;
document.getElementById(pfn).disabled = true;
document.getElementById(pfy).disabled = true;
document.getElementById(userin).style.backgroundColor = ‘#78e154’;
}
else{
document.getElementById(pfn).disabled = true;
document.getElementById(pfy).disabled = true;
document.getElementById(pfy).checked = false;
document.getElementById(pfn).checked = true;
document.getElementById(userin).style.backgroundColor = ‘#de4948’;
}
}
</script>


snip


<tr>
<td>1</td>
<td></td>
<td></td>
<td>5V PS</td>
<td>4</td>
<td><input style=“width: 60px; font-weight: bold;” type=“text” id=“UserIn1” onclick=“this.value=‘’; this.style.backgroundColor = ‘#fff’;” onblur=‘PassFail(4,6,“UserIn1”,“pfy1”,“pfn1”)’/></td>
<td>6</td>
<td> </td>
<td>50030500122</td><td style=“text-align: center; background: #78e154;”><input type=“radio” id=“pfy1” /></td><td style=“text-align: center; background: #de4948;”><input type=“radio” id=“pfn1” /></td>

</tr>
<tr>
<td>2</td>
<td></td>
<td></td>
<td>3.3V PS</td>
<td>3.2</td>
<td><input style=“width: 60px; font-weight: bold;” type=“text” id=“UserIn2” onclick=“this.value=‘’; this.style.backgroundColor = ‘#fff’;” onblur=‘PassFail(3.2,3.4,“UserIn2”,“pfy2”,“pfn2”)’/></td>
<td>3.4</td>
<td> </td>
<td>50030500122</td><td style=“text-align: center; background: #78e154;”><input type=“radio” id=“pfy2” /></td><td style=“text-align: center; background: #de4948;”><input type=“radio” id=“pfn2” /></td>

&lt;/tr&gt;

so as you can see there in an input box that they enter a number into, and it evaluates the number, changes the input background color, and selects/disables the appropriate checkbox. for pass/fail.

Now, at the end I need the submit button to turn red and say FAIL if ANY of the FAIL radios are selected, or green and say PASS if NONE of the fail radios are selected. I hope this all makes sense. And thanks for the help!

Hi,
you are using form controls. You want another form control, a submit button. So I’m going to assume this is actually a form, rather than just a Javascripted feedback mechanism.

Quickie idea (untested!!, written in browser):


function setSubmit () {
    var radios = [],
         inputs = document.forms[your form id].elements,
         allInputs = inputs.length;

    for (var r=0; r<allInputs; r++) {
        if (inputs[r].type===radio) {
            radios.push(inputs[r]);
        }
    }

    var len = radios.length;
    for (var i=0; i<len; i++) {
        //if at least one pass is checked, form not blank
        if (/y/.test(radios[i].id && radios[i].checked) {
            submit.style.color='#ffffff';
            submit.style.backgroundColor='#008800';
            submit.value='PASS';
        }
        else if (/n/.test(radios[i].id && radios[i].checked) {
            submit.style.color='#ffffff';
            submit.style.backgroundColor='#cc0000';
            submit.value='FAIL';
            break; //only need one fail to FAIL, no point in checking more
        }
    }
}

It might flicker green once if it’s a long form. Again, untested but I’d start with something like this.

Also, you might be missing out on the true function of radio buttons. Radio buttons get their name from a style of buttons we used to have in places like car radio controls: mechanically, only one button could be pressed at a time. Pressing a non-pressed button would mechanically unpress any pressed button. Form radio buttons do the same: if you select one radio button from a group (a group shares a name, and your radios don’t have names yet), no others may also be selected, unlike checkboxes. (It is recommended that you set one of them ‘checked’ by default. If this doesn’t make sense for your form, consider using something else to show pass/fail to the user.)

So with that in mind, your script could probably rely on that to simply select the appropriate radio button in the group and the other will automagically deselect itself for you (I’m not 100% sure of this when the manip is done by JS rather than the user, but it should hold true).

I also wrote your Javascript in an object wrapper, just because it’s what I’m used to. You don’t have to.

Untested and written in my browser, and prolly lots of silly typos:


<form id="passfail" method="get" action="youraction.url">
    <fieldset>
        <div>
            <label for="UserIn1">Enter your number: </label>
            <input type="text" id="UserIn1" name="userin1" data-lownum="4" data-hinum="6">
        </div>
        <div class="pass">
            <input type="radio" id="pfy1" name="pf1">
            <label for="pfy1"> Pass</label>
        </div>
        <div class="fail">
            <input type="radio" id="pfn1" name="pf1">
            <labe for="pfn1"> Fail</label>
        </div>
    </fieldset>
    <fieldset>
        <div>
            <label for="UserIn2">Enter your number: </label>
            <input type="text" id="UserIn2" name="userin2" data-lownum="3.2" data-hinum="3.4">
        </div>
        <div class="pass">
            <input type="radio" id="pfy2" name="pf2"
            <label for="pfy2"> Pass</label>
        </div>
        <div class="fail">
            <input type="radio" id="pfn2" name="pf2">
            <label for="pfn2"> Fail</label>
        </div>
    </fieldset>
    <div>
        <input type="submit" value="Default text">
    </div>
</form>
<script>
    var PF = {

        //globalz
        var inputs = document.forms['passfail'].elements, //be aware some browsers add fieldset to this list, others don't
             submit = inputs[inputs.length-1];

        init: function() {
            var len = PF.inputs.length;
            for (var i=0; i<len; i++) {
                var input = PF.inputs[i];
                if (input.type===text) {
                    //modern browsers
                    if(document.addEventListener) {
                        input.addEventListener('change', PF.check, false);
                    }
                    //IE<9
                    else {
                        input.attachEvent('onchange', PF.check);
                    }
                }
            }
        },

        disable: function(radios,groupName) {
            for (var i=0; i<radios.length; i++) {
                if (radios[i].name == groupName) {
                    radios[i].disabled = true;
                }
            }
        },

        setSubmit: function() {
            var radios = [],
                 allInputs = PF.inputs.length;

            for (var r=0; r<allInputs; r++) {
                if (PF.inputs[r].type===radio) {
                    radios.push(PF.inputs[r]);
                }
            }

            var len = radios.length;
            for (var i=0; i<len; i++) {
                //if at least one pass is checked, form not blank
                if (/^pfy\\d/.test(radios[i].id && radios[i].checked) {
                    PF.submit.style.color='#ffffff';
                    PF.submit.style.backgroundColor='#008800';
                    PF.submit.value='PASS';
                }
                else if (/^pfn\\d/.test(radios[i].id && radios[i].checked) {
                    PF.submit.style.color='#ffffff';
                    PF.submit.style.backgroundColor='#cc0000';
                    PF.submit.value='FAIL';
                    break; //only need one fail to FAIL, no point in checking more
                }
            }
        },

        passFail: function(this,lownum,hinum,pfy,pfn) {
            var UserInput = parseFloat(this.value),
                 groupName = pfy.name; //name of radio group within this fieldset only

            if (isNaN(UserInput)) {
                return; //send some error message here;
            }

            if (UserInput >= lownum && UserInput <= hinum) {
                pfy.checked = true; //should uncheck the other(s)
                this.style.backgroundColor = '#78e154';
            }
            else {
                pfn.checked = true;
                this.style.backgroundColor = '#de4948';
            }

            var radios = document.forms['passfail'].elements[groupName];
            PF.disable(radios,groupName); 
            PF.setSubmit();
        },
        
        check: function(this) {
            var fieldset = this.parentNode.parentNode,
                 localInputs = fieldset.getElementsByTagName('input'), //local to clicked input only
                 lownum = parseFloat(this.getAttribute('data-lownum')),
                 hinum = parseFloat(this.getAttribute('data-hinum')),
                 pfy,
                 pfn;

            for (var i=0; i<localInputs.length; i++) {
                if (/^pfy\\d/.test(localInputs[i].id)) {
                    pfy = localInputs[i];
                    return;
                }
                else if (/^pfn\\d/.test(localInputs[i].id)) {
                    pfn = localInputs[i];
                    return;
                }
            }
            passFail(this,lownum,hinum,pfy,pfn);
        }
    };
    if(document.addEventListener) {
        window.addEventListener('load', PF.init, false);
    }
    else if(window.attachEvent) {
        window.attachEvent('onload', PF.init);
    }
</script>

CSS (in the <head>) for your inputs… instead of inline:


#passfail input[type=text] {
    width: 60px;
    font-weight: bold;
}
#passfail input[type=text]:focus {
    background-color: #fff;
}
.pass, .fail {
    text-align: center;
    background-color: #78e154;
}
.fail {
    background-color: #de4948;
}

/*hide these labels*/
.pass label, .fail label {
    position: absolute;
    left: -999em;
    height: 0;
}

I realise you posted two sets of inputs in your example but there might be many more. I also see there’s lots of other data besides the inputs. There’s nothing wrong with having a table inside a form, but I do generally encourage using forms if you’re doing “form stuff”.

If your setup were


<form id="passfail" method="post" action="actionURL">
  <table>
    ...
  </table>
</form>

Then tr’s would replace fieldsets in the code above.

There can be any number of test rows, and I am looping with PHP to create the label names to keep them all unique. I did not name the radio buttons as I’m looking for JS functionality at this point. I will absorb the scope of this over the weekend and get back. Thanks, and have a GREAT weekend!!!

:slight_smile:

I see again my code and of course, in my quickie, I forgot to create the submit variable (it’s in the longer version though).

Re names: names are pretty much required with radio buttons, as they enable radios to do what they do (act like radio buttons). Every radio button in a radio group will share the same name. So since you’ve got to have that already, it turns out your Javascript can take advantage of that, especially also if the names are very similar (all start or end with the same set of characters… easier to regex, easier to target with CSS, etc).

But nothing I’ve written above has actually been used anywhere, so very likely it wouldn’t work out of the box. However it may give you many ideas to play around with. Good luck.

These errors are bugging me, have to list them:

if (/^pfy\d/.test(radios[i].id && radios[i].checked) {
all instances of this check I’ve missed a closing )
if (/^pfy\d/.test(radios[i].id) && radios[i].checked) {

At some point I call passfail() but that needs to be PF.passfail() instead, since it needs to be referred by its object.