0

I am using an O/S plugin script that produces id's that look like array elements as follows:

<select name="serviceTypeID[1]" id="serviceTypeID[1]" ...
<select name="serviceTypeID[2]" id="serviceTypeID[2]" ... 
<select name="serviceTypeID[3]" id="serviceTypeID[3]" ...
<select name="serviceTypeID[4]" id="serviceTypeID[4]" ...
<select name="serviceTypeID[5]" id="serviceTypeID[5]" ...
<select name="serviceTypeID[6]" id="serviceTypeID[6]" ...
<select name="serviceTypeID[7]" id="serviceTypeID[7]" ...
<select name="serviceTypeID[8]" id="serviceTypeID[8]" ...
<select name="serviceTypeID[9]" id="serviceTypeID[9]" ...
<select name="serviceTypeID[10]" id="serviceTypeID[10]" ...

How can I condense the following jquery script so I do not have to hard-code-repeat the block for all 10 instances of the html select element? Can I setup a hidden form element with the index value set to it and use something like this.().val() ? This is a bit beyond my coding skills. Thanks.

    $('#serviceTypeID\\[1\\],#serviceTypeID\\[2\\],#serviceTypeID\\[3\\],#serviceTypeID\\[4\\],#serviceTypeID\\[5\\],#serviceTypeID\\[6\\],#serviceTypeID\\[7\\],#serviceTypeID\\[8\\],#serviceTypeID\\[9\\],#serviceTypeID\\[10\\]').change(function() {

      // 1st identical instance of the block
      var first = parseInt( $('#firstService\\[1\\]').val() );
      var second = parseInt( $('#secondService\\[1\\]').val() );
      var third = parseInt( $('#thirdService\\[1\\]').val() );
      if (isNaN(first)) first = 0;
      if (isNaN(second)) second = 0;
      if (isNaN(third)) third = 0;

      $('#serviceTotal\\[1\\]').val( ( first + second + third + ' Total') );

      // 2nd identical instance of the block
      first = parseInt( $('#firstService\\[2\\]').val() );
      second = parseInt( $('#secondService\\[2\\]').val() );
      third = parseInt( $('#thirdService\\[2\\]').val() );
      if (isNaN(first)) first = 0;
      if (isNaN(second)) second = 0;
      if (isNaN(third)) third = 0;

      $('#serviceTotal\\[2\\]').val( ( first + second + third + ' Total') );

      // 3rd identical instance of the block
      first = parseInt( $('#firstService\\[3\\]').val() );
      second = parseInt( $('#secondService\\[3\\]').val() );
      third = parseInt( $('#thirdService\\[3\\]').val() );
      if (isNaN(first)) first = 0;
      if (isNaN(second)) second = 0;
      if (isNaN(third)) third = 0;

      $('#serviceTotal\\[3\\]').val( ( first + second + third + ' Total') );

    //and so on up to 10 currently

      // 10th identical instance of the block
      first = parseInt( $('#firstService\\[10\\]').val() );
      second = parseInt( $('#secondService\\[10\\]').val() );
      third = parseInt( $('#thirdService\\[10\\]').val() );
      if (isNaN(first)) first = 0;
      if (isNaN(second)) second = 0;
      if (isNaN(third)) third = 0;

      $('#serviceTotal\\[10\\]').val( ( first + second + third + ' Total') );

    });
H. Ferrence
  • 7,906
  • 31
  • 98
  • 161
  • 2
    Besides the refactoring to get rid of duplication, you really should use a base argument with `parseInt`: `var x = parseInt(foo, 10);`. – Ingo Bürk Mar 30 '14 at 10:48
  • Thank you for the suggestion @IngoBürk That too is a bit beyond my current skills development progression. – H. Ferrence Mar 30 '14 at 10:50
  • It's beyond your skills to add `, 10` to every call of `parseInt`? – Ingo Bürk Mar 30 '14 at 10:52
  • As a sidenote there's something called classes that makes it easier to target many elements, and there's even a way to target elements based on what an attribute [starts with](https://api.jquery.com/attribute-starts-with-selector/) – adeneo Mar 30 '14 at 10:52
  • No, it is not beyond my skills to add that. I was simply not understanding why to do it or what it does @IngoBürk – H. Ferrence Mar 30 '14 at 10:54
  • read this. for parseInt, 10 http://stackoverflow.com/a/6676606/17447. my own post ;) – naveen Mar 30 '14 at 10:58
  • 1
    @H.Ferrence That's fair. You can google the reason in detail, but in a nutshell, not specifying a base allows Javascript to guess the base which can go very wrong if a user, for example, enters `08` instead of `8`. – Ingo Bürk Mar 30 '14 at 10:59
  • Got it now @IngoBürk. I like learning and pushing my skillset along on the client-side of development. – H. Ferrence Mar 30 '14 at 11:01

3 Answers3

2

First you need class attribute for that selects, for easier and simpler selector.

<select class="serviceType" name="serviceTypeID[1]" id="serviceTypeID[1]" ...
<select class="serviceType" name="serviceTypeID[2]" id="serviceTypeID[2]" ... 

Then you can use for loop in function call:

$('.serviceType').change(function() {

    for(var i=1; i<=10; i++){
      var first = parseInt( $('#firstService\\['+ i +'\\]').val(), 10 );
      var second = parseInt( $('#secondService\\['+ i +'\\]').val(), 10 );
      var third = parseInt( $('#thirdService\\['+ i +'\\]').val(), 10 );
      if (isNaN(first)) first = 0;
      if (isNaN(second)) second = 0;
      if (isNaN(third)) third = 0;

      $('#serviceTotal\\['+ i +'\\]').val( ( first + second + third + ' Total') );
    }
});
ogur
  • 4,526
  • 2
  • 17
  • 17
2

You can use the following fragment to loop over your select boxes with the current HTML you've got. That being said, I suspect knowing more of your HTML structure (the parents of your selects) would allow for a simpler solution.

// All select boxes.
var selects=jQuery("select[name^='serviceTypeID']").change(function() {
    // Pattern to find the counter.
    var matcher = new RegExp("serviceTypeID\\[(\\d+)\\]");

    // Invoke your code for each select box.
    jQuery.each(selects, function(index, select){
        // Get the name.
        var name=jQuery(select).prop("name");
        // Extract the counter.
        var number = matcher.exec(name)[1];

        // Your block.
        var first = parseInt( $('#firstService\\['+number+'\\]').val(), 10 );
        var second = parseInt( $('#secondService\\['+number+'\\]').val(), 10 );
        var third = parseInt( $('#thirdService\\['+number+'\\]').val(), 10 );
        if (isNaN(first)) first = 0;
        if (isNaN(second)) second = 0;
        if (isNaN(third)) third = 0;

        $('#serviceTotal\\['+number+'\\]').val( ( first + second + third + ' Total') );
    });
});
Augustus Kling
  • 3,303
  • 1
  • 22
  • 25
  • Ok, thanks @AugustusKling. I actually was implementing the 2 prior ansers and got my script to work using them. But I greatly appreciate your suggestion. – H. Ferrence Mar 30 '14 at 11:35
  • All 3 solutions are valid and correct for looping over 10 of your element box groups. I added the pattern to allow for other group counts and omitted group numbers, too. Choose the simplest solution that serves your case. – Augustus Kling Mar 30 '14 at 11:50
1

a for loop maybe?

for (var i = 1; i <= 10; i++) {
    $('#serviceTypeID\\[' + i + '\\]').change(function () {

        var first = parseInt($('#firstService\\[' + i + '\\]').val(), 10);
        var second = parseInt($('#secondService\\[' + i + '\\]').val(), 10);
        var third = parseInt($('#thirdService\\[' + i + '\\]').val(), 10);
        if (isNaN(first)) first = 0;
        if (isNaN(second)) second = 0;
        if (isNaN(third)) third = 0;

        $('#serviceTotal\\[' + i + '\\]').val((first + second + third + ' Total'));

    });
}
naveen
  • 53,448
  • 46
  • 161
  • 251
  • very cool @naveen. Thank you for the suggestion. I will try it now and post back. So greatly appreciated for your time and help. – H. Ferrence Mar 30 '14 at 10:57
  • happy to help, my friend. – naveen Mar 30 '14 at 11:31
  • I am going to accept [at]ogur's answer for the question @naveen. Not because your answer did not work -- in fact, your's does work and you responded first -- but I like the suggestion of listening for a change on class which I implemented and it worked nicely. Plus, [at]ogur is in need for more rep pts as you have accumulated a nice amount so far. So not granting you a couple more points shouldn't upset you (I hope). Have a great day and thanks for helping me... – H. Ferrence Mar 30 '14 at 11:33
  • @H.Ferrence, no problem mate. its always your question. actually ogurs answer is the more accurate condesation. i have altered mine a bit because i thought you dont need to re-calculate all fields at the change event. ogurs code re-calculates them all. mine re-calculates just the row. – naveen Mar 30 '14 at 11:36
  • Wait, don't change your answer @naveen...I actually do not want to recalculate everything -- no need to consume local resources. My visitor interaction is element-by-element, so I truly only want to calculate the "row" that changes. I am going back and tweaking my answer now that I see more clearly what yours is doing. – H. Ferrence Mar 30 '14 at 11:40