Happydevdays
Happydevdays

Reputation: 2072

jquery validation - is there a more efficient way to do this?

Background Information

I have a table where each row represents contact information. It's not necessary to have contact data, but if the user specifies an extension number, they must specify data for every field.

problem

The code I have so far to check for the majority of the fields is working.. but I have a set of checkboxes representing a day in the week. At least one day must be selected. The code right now fails... even when I have one checkbox selected, I keep getting an error.

Also i'm wondering if there's a way to simplify my IF statement that checks the checkbox status. The code is very verbose... and ugly. And here's the HTML and javascript (partial) that is called when they try to submit the form:

$('.tcdata tr').each(function(i, row) {
  var $row = $(row);
  var $ext = $row.find('input[name*="extension"]');
  if ($ext.val()) {
    //extension data has been defined.. make sure you have start time / end time
    var $start = $row.find('input[name*="starttime"]');
    var $end = $row.find('input[name*="endtime"]');
    var $domain = $row.find('input[name*="domain"]');
    if (!$start.val() || !$end.val() || !$domain.val()) {
      $(".btn-warning").html("Whoops! Every time condition must have a start / end time, and a domain");
      e.preventDefault();
      return;
    }

    //check days of week. 
    var $dow_m = $row.find('input[name*="dow_m"]');
    var $dow_t = $row.find('input[name*="dow_t"]');
    var $dow_w = $row.find('input[name*="dow_w"]');
    var $dow_r = $row.find('input[name*="dow_r"]');
    var $dow_f = $row.find('input[name*="dow_f"]');
    var $dow_s = $row.find('input[name*="dow_s"]');
    var $dow_s = $row.find('input[name*="dow_n"]');
    if ((!$("#dow_m").is(':checked')) && (!$("#dow_t").is(':checked')) && (!$("#dow_w").is(':checked')) && (!$("#dow_r").is(':checked')) && (!$("#dow_f").is(':checked')) && (!$("#dow_s").is(':checked')) && (!$("#dow_n").is(':checked'))) {
      //nothing selected
      $(".btn-warning").html("Whoops! Every time condition must have a day of week assign to it");
      e.preventDefault();
      return;
    }


  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table table-bordered table-hover tcdata">
  <tbody>
    <tr>
      <td colspan="6">
        <h3>Time Conditions</h3>
      </td>
    </tr>
    <tr>
      <td colspan="6">Default Rule:</td>
    </tr>

    <tr id="time_conditions">
      <td><input class="form-control starttc tcdata" type="input" placeholder="UTC Start Time (format 00:00:00)" name="starttime" id="starttime"></td>
      <td><input class="form-control tcdata" type="input" placeholder="UTC End Time (format 00:00:00)" name="endtime" id="endtime"></td>
      <td><input class="form-control tcdata" type="input" placeholder="Extension" name="extension" id="extension"></td>
      <td><input class="form-control tcdata" type="input" placeholder="Domain" name="domain" id="domain"></td>
      <td>
        <label class="checkbox-inline"><b>Days of Week:</b></label>
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_m">Mon&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_t">Tue&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_w">Wed&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_r">Thu&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_f">Fri&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_s">Sat&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_t">Sun&nbsp;
      </td>
      <td><button id="addtc" type="button" class="btn btn-success btn-circle"><i class="fa fa-plus"></i></button></td>
    </tr>
    <tr class="showAdditionalRulesLabel" style="">
      <td colspan="6">Addtional Rules:</td>
    </tr>
    <tr>
      <td><input class="form-control starttc tcdata" type="input" placeholder="UTC Start Time (format 00:00:00)" name="starttime2"></td>

      <td><input class="form-control tcdata" type="input" placeholder="UTC End Time (format 00:00:00)" name="endtime2"></td>
      <td><input class="form-control tcdata" type="input" placeholder="Extension" name="extension2"></td>
      <td><input class="form-control tcdata" type="input" placeholder="Domain" name="domain2"></td>
      <td colspan="2"><label class="checkbox-inline"><b>Days of Week:</b></label><input class="checkbox-inline tcdata" type="checkbox" name="dow_m2">Mon&nbsp;<input class="checkbox-inline tcdata" type="checkbox" name="dow_t2">Tue&nbsp;<input class="checkbox-inline tcdata"
          type="checkbox" name="dow_w2">Wed&nbsp;<input class="checkbox-inline tcdata" type="checkbox" name="dow_r2">Thu&nbsp;<input class="checkbox-inline tcdata" type="checkbox" name="dow_f2">Fri&nbsp;<input class="checkbox-inline tcdata" type="checkbox"
          name="dow_s2">Sat&nbsp;<input class="checkbox-inline tcdata" type="checkbox" name="dow_n2">Sun&nbsp;
      </td>
    </tr>

    <tr id="submitbtnsection">
      <td colspan="6"><input type="submit" name="submit" id="submit" class="btn btn-primary" value="Assign"></td>
    </tr>

  </tbody>
</table>

One additional comment - in case it helps... You'll notice that for each row in my table the names of the fields are identical except that the number at the end is incremented. So for example:

  name="dow_w"
  name="dow_w2"

these rows are generated dynamically by jquery... but i don't think it's relevant so I haven't included the code. The html code you see above is the RENDERED html... so it's pretty accurate.

Any help figuring out where my bug is would be appreciated.

Upvotes: 3

Views: 62

Answers (1)

Mikey
Mikey

Reputation: 6766

  1. Each rule is made up of multiple <tr> -- so it doesn't really make sense to loop over each of them. Instead group your set of <tr> using <tbody> and loop over the multiple <tbody>.

  2. I think the proper way to have inputs having same names is to append [n] (where n is a number). This way all inputs with same [n] are considered related.

  3. Chances are you want inputs having same names to have similar styles. Instead of using IDs, use classes.

  4. I find the easiest way to cache elements with [n] at the end is to use [name^=name] where ^= means "start with".

  5. You can use a combination of the ^= selector and :checked to get the days that were checked. And then use length property to count how many were selected.

HTML (1-3)

<table class="table table-bordered table-hover tcdata">
  <tbody>
    <tr>
      <td colspan="6">
        <h3>Time Conditions</h3></td>
    </tr>
    <tr>
      <td colspan="6">Default Rule:</td>
    </tr>

    <tr id="time_conditions">
      <td>
        <input class="form-control starttc tcdata starttime" type="input" placeholder="UTC Start Time (format 00:00:00)" name="starttime[0]">
      </td>
      <td>
        <input class="form-control tcdata endtime" type="input" placeholder="UTC End Time (format 00:00:00)" name="endtime[0]">
      </td>
      <td>
        <input class="form-control tcdata extension" type="input" placeholder="Extension" name="extension[0]">
      </td>
      <td>
        <input class="form-control tcdata" type="input" placeholder="Domain" name="domain[0]" id="domain">
      </td>
      <td>
        <label class="checkbox-inline"><b>Days of Week:</b></label>
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_m[0]">Mon&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_t[0]">Tue&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_w[0]">Wed&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_r[0]">Thu&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_f[0]">Fri&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_s[0]">Sat&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_t[0]">Sun&nbsp;
      </td>
      <td>
        <button id="addtc" type="button" class="btn btn-success btn-circle"><i class="fa fa-plus"></i></button>
      </td>
    </tr>

  </tbody>
  <tbody>
    <tr class="showAdditionalRulesLabel" style="">
      <td colspan="6">Addtional Rules:</td>
    </tr>
    <tr>
      <td>
        <input class="form-control starttc tcdata" type="input" placeholder="UTC Start Time (format 00:00:00)" name="starttime[1]">
      </td>

      <td>
        <input class="form-control tcdata" type="input" placeholder="UTC End Time (format 00:00:00)" name="endtime[1]">
      </td>
      <td>
        <input class="form-control tcdata" type="input" placeholder="Extension" name="extension[1]">
      </td>
      <td>
        <input class="form-control tcdata" type="input" placeholder="Domain" name="domain[1]">
      </td>
      <td colspan="2">
        <label class="checkbox-inline"><b>Days of Week:</b></label>
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_m[1]">Mon&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_t[1]">Tue&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_w[1]">Wed&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_r[1]">Thu&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_f[1]">Fri&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_s[1]">Sat&nbsp;
        <input class="checkbox-inline tcdata" type="checkbox" name="dow_n[1]">Sun&nbsp;
      </td>
    </tr>

    <tr id="submitbtnsection">
      <td colspan="6">
        <input type="button" name="submit" id="submit" class="btn btn-primary" value="Assign">
      </td>
    </tr>

  </tbody>
</table>

JavaScript (4-5)

$('.tcdata tbody').each(function() {
    // $row is kinda misleading - better to say: $tbody
    var $row = $(this);
    // cleaner to store all the elements you need together
    var $ext = $row.find('[name^="extension"]'),
      $start = $row.find('[name^="starttime"]'),
      $end = $row.find('[name^="endtime"]'),
      $domain = $row.find('[name^="domain"]');

    // check if the user specifies an extension number
    if ($ext.val()) {
      // they must specify data for every field
      if (!$start.val() || !$end.val() || !$domain.val()) {
        $warning.html("Whoops! Every time condition must have a start / end time, and a domain");
        e.preventDefault();
        return;
      }
      // and at least one day must be selected 
      if (!$row.find('[name^=dow_]:checked').length) {
        $warning.html("Whoops! Every time condition must have a day of week assign to it");
        e.preventDefault();
        return;
      }
    }
});

Demo

Upvotes: 1

Related Questions