0

I have a form with a varying number of inputs, some visible and some hidden (they're conditional based on selected options and radio controls). I have jQuery script below that's pulling through all of the visible inputs on the form.

EDIT more of the script as requested.

var formInputs  = jQuery('#Enquire :input:not(button):visible');

var enquiry = validateInputs(formInputs);

function validateInputs(inputs){
    var nullCount  = 0;
    var errorCount = 0;
    var reqdFields = {};
    var formInputs = {};
    var firstError = "";
    var text = "";
    inputs.each(function(){
        if(jQuery(this).is(":visible")){ // will remove once I've got the answer
            var name = jQuery(this).attr("name");
            var value = jQuery(this).val();

            if(jQuery(this).hasClass("error")){ errorCount++; }

            var reqd = jQuery(this).attr('required');

            var num = jQuery(this).attr('number');
            var fieldType = jQuery(this).attr('type');
            var errorLabel = "<label id=\"" + name + "-error\" class=\"error\" for=\"" + name + "\">This field is required.</label>";
            var numerrorLabel = "<label id=\"" + name + "-error\" class=\"error\" for=\"" + name + "\">This field can only contain numeric characters.</label>";
            //check if the field is required
            if(typeof reqd !== typeof undefined && reqd !== false){
                //check if the field's value is empty
                if(value == null || value == ""){
                    nullCount++;
                    if(!(jQuery(this).hasClass("error"))){
                        debugLog("adding error class");
                        //perform the error report on the field
                        jQuery(this).addClass("error");
                        jQuery(this).after(errorLabel);
                    }
                }
            }
            //check if the field is a number field
            if(typeof num !== typeof undefined && num !== false){
                //check if the field already has an error (null)
                if(!(jQuery(this).hasClass("error"))){
                    if(!isNumeric(value)){
                        debugLog("adding error class");
                        //perform the error report on the field
                        jQuery(this).addClass("error");
                        jQuery(this).after(numerrorLabel);
                   }

                }
            }
            //check if the field value is not empty
            if(jQuery(this).val() != ""){
                debugLog("Visible Field" + jQuery(this).attr("id"));
                //check if the field is a checkbox / radio field which doesn't use IDs
                if(fieldType == "radio" && jQuery(this).prop("checked")){
                    outputdata[name] = value;
                }
                else{
                    outputdata[name] = value;
                }
            }
            else{
                //here we flag the first required field's ID so we can scroll to it later
                if(nullCount == 1){
                    firstError = jQuery(this).attr("id");
                    debugLog("First Error" + firstError);
                }
                debugLog("Null value for "+name);
            }

        }
    });
    debugLog(nullCount);
    debugLog(reqdFields);    
    debugLog(errorCount);
    debugLog(outputdata);
    Errors = errorCount;
    if(nullCount !== 0){
        debugLog("throw Error on screen");
        jQuery('html, body').animate({
            scrollTop: (jQuery("#"+firstError).offset().top)-40
        }, 1000);
    }else{
        return outputdata;
    }
};

What I've found is that everything seems to work fine except for the radio buttons and checkboxes as it seems to default the last input with the same name. HTML below:

<form role="form" class="clearfix Form DonationForm" id="Enquire">
    <fieldset>

        <div class="form-group col-lg-12 no-padding">
            <div class="form-group col-lg-2 no-left-padding no-margin">
              <label for="Title" class="control-label col-sm-12 no-padding">Title</label>
              <div class="col-sm-12 no-padding">
                <select id="Title" name="Title" class="form-control" required type="select">
                    <option value="">Title:</option>
                    <option value="Mr">Mr</option>
                    <option value="Mrs">Mrs</option>
                    <option value="Miss">Miss</option>
                    <option value="Ms">Ms</option>
                    <option value="Dr">Dr</option>
                    <option value="Prof">Prof</option>
                    <option value="Hon">Hon</option>
                    <option value="Rev">Rev</option>
                </select>
              </div>
            </div>

            <div class="form-group col-lg-5 no-padding no-margin">
              <label for="FirstName" class="control-label col-sm-12 no-padding">First Name</label>
              <div class="col-sm-12 no-padding">
                <input type="text" class="form-control" id="FirstName" name="FirstName" placeholder="First Name" required minlength="2">

              </div>
            </div>

            <div class="form-group col-lg-5 no-right-padding no-margin">
              <label for="Surname" class="control-label col-sm-12 no-padding">Surname</label>
              <div class="col-sm-12 no-padding">
                <input type="text" class="form-control" id="Surname" name="Surname" placeholder="Surname" required minlength="2">

              </div>
            </div>
        </div>
        <div class="form-group col-lg-6 no-padding">
          <label class="control-label col-sm-12 no-padding" for="EnquiryType">Enquiry Type</label>
          <div class="controls text-left col-sm-6 no-left-padding">
            <label><input type="radio" class="EnquiryType" name="EnquiryType" id="Sales" value="Sales" required>Sales</label>
          </div>
          <div class="controls text-left col-sm-6 no-right-padding">
            <label><input type="radio" class="EnquiryType" name="EnquiryType" id="Service" value="Service" required>Service</label>
          </div>
        </div>

        <div class="form-group">
            <div class="controls col-sm-12 no-padding">
                <input type="hidden" id="ReferenceNo" name="ReferenceNo" value="<?php echo genTicketString(); ?>">
                <a class="btn btn-success" href="javascript:;" id="EnquireBtn">Enquire Now</a>
                <!--input class="btn btn-success" type="submit" value="Enquire Now"-->
            </div>
        </div>
    </fieldset>
</form>

I'm currently logging everything to the console to watch what is happening and no matter what my selection is above, the output is always EnquiryType: Service

In an attempt to "catch" this particular issue, I had changed this:

if(jQuery(this).val() != ""){
    debugLog("Visible Field" + jQuery(this).attr("id"));
    formInputs[name] = value;
}   

To this:

if(jQuery(this).val() != ""){
    debugLog("Visible Field" + jQuery(this).attr("id"));
    //check if the field is a checkbox / radio field which doesn't use IDs
    if(fieldType == "radio" && jQuery(this).prop("checked")){
        formInputs[name] = value;
    }
    else{
        formInputs[name] = value;
    }
}   

Are there any suggestions? I'd prefer to keep the script as dynamic as possible and it works great for all other input types so I'd like to fix this please.

Daniel
  • 2,167
  • 5
  • 23
  • 44
  • Please read [How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). For short, please make a runnable snippet that show the exact problem you have. – Ionut Necula Jul 17 '17 at 14:05
  • Hi @Ionut my script is very long and the form equally so. When I've posted questions with the full code in the past I was flamed for doing so. I opted to illustrate the area where the issue appears to lie rather than the entire form and respective code – Daniel Jul 17 '17 at 14:08
  • A stripped down test case example would be quite helpful in finding your problem. Meantime, a question: You're already selecting inputs that specifically are ':visible'. So why the redundant check that an element is visible in the loop in validateInputs? – BrianFreud Jul 17 '17 at 14:09
  • I see how that is redundant, thanks @BrianFreud – Daniel Jul 17 '17 at 14:10
  • @Daniel, I didn't say to post the whole code here, just the minimum pieces of code into a runnable and demonstrative snippet of the issue you say you have. – Ionut Necula Jul 17 '17 at 14:14
  • Appreciate the feedback @Ionut, I've done so now and hopefully made it easier to understand. – Daniel Jul 17 '17 at 14:19
  • Based on what you'd originally posted, there is no visible error: https://jsfiddle.net/6d25Lkp4/ – BrianFreud Jul 17 '17 at 14:20
  • @BrianFreud, viewing it as you have put it makes the bug blindly obvious. If the first radio button is selected, assuming the `each` loop goes in sequence, the object gets a property `formInputs["Enquiry"] = "Sales" then it loops through the second and finds that the same property is blank. Do you agree? – Daniel Jul 17 '17 at 14:23
  • Where is the `#donate` element? As I said, please make a runnable snippet. – Ionut Necula Jul 17 '17 at 14:23
  • @Ionut In that fiddle, #donate === the #testcase div. Daniel If I recall correctly, it's a safe assumption that jQuery is stepping through the matches in DOM tree order. (and that fiddle is what we meant by a test example :) ) But I'm not quite following your question; which object are you referring to? – BrianFreud Jul 17 '17 at 14:26
  • @Ionut I've added more of the form with more fields – Daniel Jul 17 '17 at 14:29
  • @BrianFreud great, sorry if I'm being daft, the object I'm referring to is the `outputdata` object. I was saying I think that the loop is causing the second instance of the "EnquiryType" radio button to overwrite the first. This is an issue if the first is selected. – Daniel Jul 17 '17 at 14:31
  • Well, in regards to simply looping through and examining the info, per your original question, jQuery's handling both EnquiryType radio inputs, as you can see in the fiddle's output. But yes, in terms of what would actually be submitted, it's likely a really bad idea to have two form elements both with the same name attribute. – BrianFreud Jul 17 '17 at 14:35
  • @BrianFreud, what method would you use to determine which radio button of a "form-group" was selected? – Daniel Jul 17 '17 at 14:38
  • I'd group the radio buttons into a fieldset (see the first answer in https://stackoverflow.com/questions/28543752/multiple-radio-button-groups-in-one-form ), then it's simple. Assuming that same answer's HTML, to get the selected element in group1, use $('#group1 :checked') – BrianFreud Jul 17 '17 at 14:48

1 Answers1

0

The issue lay in my desire to not make multiple if() statements:

//check if the field value is not empty
if(jQuery(this).val() != ""){
    debugLog("Visible Field" + jQuery(this).attr("id"));
    //check if the field is a checkbox / radio field which doesn't use IDs
    if(fieldType == "radio" && jQuery(this).prop("checked")){
        outputdata[name] = value;
    }
    else{
        outputdata[name] = value;
    }
}

The above portion of code would get the name and value of the first radio and it would be great, when it looped back for the next input it would overwrite that previously assigned name and value. I changed the if() statement to below and my problem is resolved.

//check if the field is a checkbox / radio field which doesn't use IDs
if(fieldType == "radio")
{
    if(jQuery(this).prop("checked"))
    {
        fieldid = jQuery(this).attr("id").toString();
        if (document.getElementById(fieldid).checked)
        {
            formInputs[name] = value;
        }
    }
}
Daniel
  • 2,167
  • 5
  • 23
  • 44