Matthew
Matthew

Reputation: 271

Is there a way to combine these similar jQuery event listener functions?

I have multiple jquery event listener functions that either show or hide a checkmark button based on if there is any input in the input box. The functions are practically identical minus the ID names. I'm wondering if there's a way to combine these similar functions into one, maybe using a for loop or forEach method? Any advice on how to achieve this is greatly appreciated! Code is listed down below but I also made a codepen sample.

$("#chwValue").on("input", function() {
  $("#addChw").removeAttr("style");
  if ($(this).val() === "") {
    $("#addChw").hide();
  }
});

$("#eleValue").on("input", function() {
  $("#addEle").removeAttr("style");
  if ($(this).val() === "") {
    $("#addEle").hide();
  }
});

$("#stmValue").on("input", function() {
  $("#addStm").removeAttr("style");
  if ($(this).val() === "") {
    $("#addStm").hide();
  }
});

$("#hhwValue").on("input", function() {
  $("#addHhw").removeAttr("style");
  if ($(this).val() === "") {
    $("#addHhw").hide();
  }
});

$("#gasValue").on("input", function() {
  $("#addGas").removeAttr("style");
  if ($(this).val() === "") {
    $("#addGas").hide();
  }
});

$("#wtrValue").on("input", function() {
  $("#addWtr").removeAttr("style");
  if ($(this).val() === "") {
    $("#addWtr").hide();
  }
});

$("#peakChwValue").on("input", function() {
  $("#addPeakChw").removeAttr("style");
  if ($(this).val() === "") {
    $("#addPeakChw").hide();
  }
});

$("#laborValue").on("input", function() {
  $("#addLabor").removeAttr("style");
  if ($(this).val() === "") {
    $("#addLabor").hide();
  }
});
.checkMark:hover {
  cursor: pointer;
  transition: transform 0.2s;
  transform: scale(1.1)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" />

<table id="tableData" class="table text-light text-end table-borderless inputTable">
  <thead>
    <tr class='text-center bordered'>
      <th></th>
      <th class="bordered" scope="col">CHW
        <span class='units'>[tonhr]</span>
      </th>
      <th class="bordered" scope="col">ELE
        <span class='units'>[kWh]</span>
      </th>
      <th class="bordered" scope="col">STM
        <span class='units'>[lb]</span>
      </th>
      <th class="bordered" scope="col">HHW
        <span class='units'>[mmbtu]</span>
      </th>
      <th class="bordered" scope="col">GAS
        <span class='units'>[CCF]</span>
      </th>
      <th class="bordered" scope="col">WTR
        <span class='units'>[kgal]</span>
      </th>
      <th class="bordered" scope="col">Peak CHW
        <span class='units'>[ton]</span>
      </th>
      <th class="bordered" scope="col">Labor
        <span class='units'>[Hours]</span>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th style="width: 100px" class="bordered">Baseline</th>
      <td class="text-center inputBorder">
        <input type="text" id="chwValue" class="chwInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="eleValue" class="eleInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="stmValue" class="stmInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="hhwValue" class="hhwInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="gasValue" class="gasInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="wtrValue" class="wtrInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="peakChwValue" class="peakChwInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="laborValue" class="laborInput">
      </td>
    </tr>
    <tr class='text-center borderTop'>
      <td></td>
      <td>
        <i id="addChw" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addEle" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addStm" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addHhw" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addGas" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addWtr" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addPeakChw" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addLabor" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
    </tr>
  </tbody>
</table>

Upvotes: 0

Views: 50

Answers (5)

Albab
Albab

Reputation: 384

How about this?

$("#chwValue, #eleValue, #stmValue, #hhwValue, #gasValue, #wtrValue, #peakChwValue, #laborValue").on("input", function() {

  //get the id selector from the id value (everything before 'Value')
  let idName = $(this).attr('id').split('Value')[0]

  //capitalize the first character
  idName = idName[0].toUpperCase() + idName.slice(1);

  //add the id selector dynamically
  $("#add"+idName).removeAttr("style");
  if ($(this).val() === "") {
    $("#add"+idName).hide();
  }
});

$("#chwValue, #eleValue, #stmValue, #hhwValue, #gasValue, #wtrValue, #peakChwValue, #laborValue").on("input", function() {

      //get the id selector from the id value (everything before 'Value')
      let idName = $(this).attr('id').split('Value')[0]

      //capitalize the first character
      idName = idName[0].toUpperCase() + idName.slice(1);

      //add the id selector dynamically
      $("#add"+idName).removeAttr("style");
      if ($(this).val() === "") {
        $("#add"+idName).hide();
      }
    });
.checkMark:hover {
  cursor: pointer;
  transition: transform 0.2s;
  transform: scale(1.1)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" />

<table id="tableData" class="table text-light text-end table-borderless inputTable">
  <thead>
    <tr class='text-center bordered'>
      <th></th>
      <th class="bordered" scope="col">CHW
        <span class='units'>[tonhr]</span>
      </th>
      <th class="bordered" scope="col">ELE
        <span class='units'>[kWh]</span>
      </th>
      <th class="bordered" scope="col">STM
        <span class='units'>[lb]</span>
      </th>
      <th class="bordered" scope="col">HHW
        <span class='units'>[mmbtu]</span>
      </th>
      <th class="bordered" scope="col">GAS
        <span class='units'>[CCF]</span>
      </th>
      <th class="bordered" scope="col">WTR
        <span class='units'>[kgal]</span>
      </th>
      <th class="bordered" scope="col">Peak CHW
        <span class='units'>[ton]</span>
      </th>
      <th class="bordered" scope="col">Labor
        <span class='units'>[Hours]</span>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th style="width: 100px" class="bordered">Baseline</th>
      <td class="text-center inputBorder">
        <input type="text" id="chwValue" class="chwInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="eleValue" class="eleInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="stmValue" class="stmInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="hhwValue" class="hhwInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="gasValue" class="gasInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="wtrValue" class="wtrInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="peakChwValue" class="peakChwInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="laborValue" class="laborInput">
      </td>
    </tr>
    <tr class='text-center borderTop'>
      <td></td>
      <td>
        <i id="addChw" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addEle" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addStm" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addHhw" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addGas" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addWtr" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addPeakChw" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addLabor" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
    </tr>
  </tbody>
</table>

Upvotes: 0

Kinglish
Kinglish

Reputation: 23654

Store the relationships in an array of objects and iterate through.

let objs = [
{'chwValue': 'addChw'},
{'eleValue': 'addEle'},
{'stmValue': 'addStm'},
{'hhwValue': 'addHhw'},
{'gasValue': 'addGas'},
{'wtrValue': 'addWtr'},
{'peakChwValue': 'addPeakChw'},
{'laborValue': 'addLabor'}];

objs.forEach(e => {
  let [input, el] = Object.entries(e)[0];
  $(`#${input}`).on("input", function() {
    $(`#${el}`).removeAttr("style");
    if ($(this).val() === "") $(`$${el}`).hide();
  });
});
 
.checkMark:hover {
  cursor: pointer;
  transition: transform 0.2s;
  transform: scale(1.1)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<table id="tableData" class="table text-light text-end table-borderless inputTable">
  <thead>
    <tr class='text-center bordered'>
      <th></th>
      <th class="bordered" scope="col">CHW
        <span class='units'>[tonhr]</span>
      </th>
      <th class="bordered" scope="col">ELE
        <span class='units'>[kWh]</span>
      </th>
      <th class="bordered" scope="col">STM
        <span class='units'>[lb]</span>
      </th>
      <th class="bordered" scope="col">HHW
        <span class='units'>[mmbtu]</span>
      </th>
      <th class="bordered" scope="col">GAS
        <span class='units'>[CCF]</span>
      </th>
      <th class="bordered" scope="col">WTR
        <span class='units'>[kgal]</span>
      </th>
      <th class="bordered" scope="col">Peak CHW
        <span class='units'>[ton]</span>
      </th>
      <th class="bordered" scope="col">Labor
        <span class='units'>[Hours]</span>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th style="width: 100px" class="bordered">Baseline</th>
      <td class="text-center inputBorder">
        <input type="text" id="chwValue" class="chwInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="eleValue" class="eleInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="stmValue" class="stmInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="hhwValue" class="hhwInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="gasValue" class="gasInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="wtrValue" class="wtrInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="peakChwValue" class="peakChwInput">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="laborValue" class="laborInput">
      </td>
    </tr>
    <tr class='text-center borderTop'>
      <td></td>
      <td>
        <i id="addChw" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addEle" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addStm" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addHhw" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addGas" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addWtr" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addPeakChw" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
      <td>
        <i id="addLabor" style="display: none" class="far fa-check-circle fa-3x checkMark"></i>
      </td>
    </tr>
  </tbody>
</table>

Upvotes: 0

tantalum
tantalum

Reputation: 2452

You can try something like this:

var mappings = { //Need a better name
  '#chwValue': '#addChw',
  '#hhwValue': '#addHhw'
  // Add the rest of the mappings here
}

Object.keys(mappings).forEach(function(key) {
  var value = mappings[key];
  $(key).on("input", function() {
    $(value).removeAttr("style");
    if ($(this).val() === "") {
      $(value).hide();
    }
  });
});

Upvotes: 1

Barmar
Barmar

Reputation: 780673

Give all the inputs a common class. Give them an attribute that refers to the related addXxx element.

$(".inputValue").on("input", function() {
  let rel = $($(this).data("add"));
  rel.removeAttr("style");
  if ($(this).val() === "") {
    rel.hide();
  }
});
.checkMark:hover {
  cursor: pointer;
  transition: transform 0.2s;
  transform: scale(1.1)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="tableData" class="table text-light text-end table-borderless inputTable">
  <thead>
    <tr class='text-center bordered'>
      <th></th>
      <th class="bordered" scope="col">CHW
        <span class='units'>[tonhr]</span>
      </th>
      <th class="bordered" scope="col">ELE
        <span class='units'>[kWh]</span>
      </th>
      <th class="bordered" scope="col">STM
        <span class='units'>[lb]</span>
      </th>
      <th class="bordered" scope="col">HHW
        <span class='units'>[mmbtu]</span>
      </th>
      <th class="bordered" scope="col">GAS
        <span class='units'>[CCF]</span>
      </th>
      <th class="bordered" scope="col">WTR
        <span class='units'>[kgal]</span>
      </th>
      <th class="bordered" scope="col">Peak CHW
        <span class='units'>[ton]</span>
      </th>
      <th class="bordered" scope="col">Labor
        <span class='units'>[Hours]</span>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th style="width: 100px" class="bordered">Baseline</th>
      <td class="text-center inputBorder">
        <input type="text" id="chwValue" class="chwInput inputValue" data-add="#addChw">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="eleValue" class="eleInput inputValue" data-add="#addEle">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="stmValue" class="stmInput inputValue" data-add="#addStm">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="hhwValue" class="hhwInput inputValue" data-add="#addHhw">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="gasValue" class="gasInput inputValue" data-add="#addGas">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="wtrValue" class="wtrInput inputValue" data-add="#addWtr">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="peakChwValue" class="peakChwInput inputValue" data-add="#addPeakChw">
      </td>
      <td class="text-center inputBorder">
        <input type="text" id="laborValue" class="laborInput inputValue" data-add="#addLabor">
      </td>
    </tr>
    <tr class='text-center borderTop'>
      <td></td>
      <td>
        <i id="addChw" style="display: none" class="far fa-check-circle fa-3x checkMark">x</i>
      </td>
      <td>
        <i id="addEle" style="display: none" class="far fa-check-circle fa-3x checkMark">x</i>
      </td>
      <td>
        <i id="addStm" style="display: none" class="far fa-check-circle fa-3x checkMark">x</i>
      </td>
      <td>
        <i id="addHhw" style="display: none" class="far fa-check-circle fa-3x checkMark">x</i>
      </td>
      <td>
        <i id="addGas" style="display: none" class="far fa-check-circle fa-3x checkMark">x</i>
      </td>
      <td>
        <i id="addWtr" style="display: none" class="far fa-check-circle fa-3x checkMark">x</i>
      </td>
      <td>
        <i id="addPeakChw" style="display: none" class="far fa-check-circle fa-3x checkMark">x</i>
      </td>
      <td>
        <i id="addLabor" style="display: none" class="far fa-check-circle fa-3x checkMark">x</i>
      </td>
    </tr>
  </tbody>
</table>

Upvotes: 1

Rory McCrossan
Rory McCrossan

Reputation: 337550

To achieve this in a more DRY manner you can relate the cells in the columns by their index. When an input element raises an input event you can capture its index within the parent tr, then retrieve the corresponding icon cell from the following row by that same index. Something like this:

let $iconCells = $('.icon-row td');

$('.input-row input').on('input', e => {
  let $input = $(e.target)
  let index = $input.closest('td').index();
  $iconCells.eq(index).find('i').toggle($input.val().length > 0);
});
.checkMark:hover {
  cursor: pointer;
  transition: transform 0.2s;
  transform: scale(1.1)
}

.icon-row i {
  display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" />
<table id="tableData" class="table text-light text-end table-borderless inputTable">
  <thead>
    <tr class='text-center bordered'>
      <th></th>
      <th class="bordered" scope="col">
        CHW
        <span class='units'>[tonhr]</span>
      </th>
      <th class="bordered" scope="col">
        ELE
        <span class='units'>[kWh]</span>
      </th>
      <th class="bordered" scope="col"> 
        STM
        <span class='units'>[lb]</span>
      </th>
      <th class="bordered" scope="col">
        HHW
        <span class='units'>[mmbtu]</span>
      </th>
      <th class="bordered" scope="col">
        GAS
        <span class='units'>[CCF]</span>
      </th>
      <th class="bordered" scope="col">
        WTR
        <span class='units'>[kgal]</span>
      </th>
      <th class="bordered" scope="col">
        Peak CHW
        <span class='units'>[ton]</span>
      </th>
      <th class="bordered" scope="col">
        Labor
        <span class='units'>[Hours]</span>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr class="input-row">
      <th style="width: 100px" class="bordered">Baseline</th>
      <td class="text-center inputBorder">
        <input type="text" name="chwValue" class="chwInput" /> 
      </td>
      <td class="text-center inputBorder">
        <input type="text" name="eleValue" class="eleInput" />
      </td>
      <td class="text-center inputBorder">
        <input type="text" name="stmValue" class="stmInput" />
      </td>
      <td class="text-center inputBorder">
        <input type="text" name="hhwValue" class="hhwInput" />
      </td>
      <td class="text-center inputBorder">
        <input type="text" name="gasValue" class="gasInput" />
      </td>
      <td class="text-center inputBorder">
        <input type="text" name="wtrValue" class="wtrInput" />
      </td>
      <td class="text-center inputBorder">
        <input type="text" name="peakChwValue" class="peakChwInput" /> 
      </td>
      <td class="text-center inputBorder">
        <input type="text" name="laborValue" class="laborInput" />
      </td>
    </tr>
    <tr class="text-center borderTop icon-row">
      <td></td>
      <td><i class="far fa-check-circle fa-3x checkMark"></i></td>
      <td><i class="far fa-check-circle fa-3x checkMark"></i></td>
      <td><i class="far fa-check-circle fa-3x checkMark"></i></td>
      <td><i class="far fa-check-circle fa-3x checkMark"></i></td>
      <td><i class="far fa-check-circle fa-3x checkMark"></i></td>
      <td><i class="far fa-check-circle fa-3x checkMark"></i></td>
      <td><i class="far fa-check-circle fa-3x checkMark"></i></td>
      <td><i class="far fa-check-circle fa-3x checkMark"></i></td>
    </tr>
  </tbody>
</table>

Upvotes: 0

Related Questions