1

I want to change a query string from

?firstArray[]=0001&firstArray[]=0002&secondArray[]=0003&secondArray[]=0004 to ?firstArray=0001,0002&secondArray=0003,0004

I think I'm almost there, but the problem I have is that the array values are the same for both arrays after my javascript is done processing the form. Here's the form:

<form method="get" action="" class="productFilter">
    <input type="checkbox" name="firstArray[]" id="" value="0001">0001
    <input type="checkbox" name="firstArray[]" id="" value="0002">0002
    <input type="checkbox" name="secondArray[]" id="" value="0003">0003
    <input type="checkbox" name="secondArray[]" id="" value="0004">0004
    <input type="submit" name="submit" value="test">
</form>

And here's the javacript/jquery:

$('.productFilter').on('submit', function() {

var newVal = [];
var seen = {};

// Gather values into array.
$('input[name$="[]"]:checked').each(function() {
    newVal.push($(this).val());
});

// Make comma-separated list of values.
var commaSeparated = newVal.join(',');
console.log(commaSeparated);

// Remove duplicates so an 'array' is only listed once in the query string.
$('input[name$="[]"]:checked').each(function() {
    var name = $(this).attr('name');
    if (seen[name]) {
        $(this).remove();
    }
    else {
        seen[name] = true;
    }
    $(this).attr('name', name.slice(0, -2)).val(commaSeparated);
});

});

I understand why my 'commaSeparated' var contains the values of both the firstArray and secondArray inputs, so when I check all the boxes, the resulting query string is:

?firstArray=0001,0002,0003,0004&secondArray=0001,0002,0003,0004 when I want it to be ?firstArray=0001,0002&secondArray=0003,0004

I'm not sure how to fix it though. I would need to store the values of the form arrays in separate variables, right? It should be noted that I don't know how many form elements there will be and what they will be called in my production code.

Marc
  • 229
  • 3
  • 13

4 Answers4

1

my strategy would be to

  • firstly, collect all the input fields that belong to arrays,
  • collect the values in a hash using the array name as key, by pushing them to an array
  • delete them from the DOM
  • then, in a second step, loop over the hash by its keys,
  • entering new form fields setting the array name as name attribute, and as value attribute the hash element value = the array containing all the values checked by the user.

This way, the server will receive for each array one field with a comma-separated list of the checked values of this array.

  $('.productFilter').on('submit', function() {

       var arrayValues = {};

      // Gather values into a hash, the keys being the array names
      $('input[name$="[]"]').each(function(index,item) {
          if (item.checked) {
            var arrayName = item.name.replace(/\[\]$/,"");
            if (!arrayValues.hasOwnProperty(arrayName)) arrayValues[arrayName] = [];
            arrayValues[arrayName].push(item.value);
          }
          $(item).remove();
      });

      // Create new form fields with the collected values per array
      Object.keys(arrayValues).forEach( function(key) { 
        $("form").append( 
           $('<input type="hidden"></input>')
              .val(arrayValues[key])
              .attr("name",key) );
      });    

  });
rplantiko
  • 2,476
  • 19
  • 21
  • I think @Marc wants to build a querystring from the form, not the other way around. You probably also want a final ")" to close the on() – JonSG Jun 13 '16 at 15:44
  • Thanks for the hint about the closing bracket: Corrected. I think @Marc wants the fields to be transported the proper way to the server. He will get precisely the query string he wants if he submits this form with the GET method after having executed the above onSubmit function (the fields will be transported correctly with a POST request, too). – rplantiko Jun 13 '16 at 15:51
  • My apologies for the late reply, but thanks alot for this lovely code, works exactly as I intended! – Marc Jun 28 '16 at 15:03
0

I think an interesting approach might be to use object properties to help uniquely sort out your parameters and values. This code uses reduce over an array of checked inputs, but you could do it with more traditional loops if you wanted.

$('.productFilter').on('submit', function() {
  // -----------------------
  // convert our select results to an array
  // -----------------------
  var checkedInputs = $.makeArray($('input[name$="[]"]:checked'));
  // -----------------------

  // -----------------------
  // convert the array of inputs into an object with nested properties
  // -----------------------
  var checkedInputsObj = checkedInputs.reduce(function(obj, item){
    obj[item.name] = (obj[item.name] || {});
    obj[item.name][item.value] = true;
    return obj
  }, {});
  // -----------------------
  
  // -----------------------
  // Build our querystring
  // -----------------------
  var qs = (function(obj){
    var _qs = "?";

    for (var param in obj){
      _qs += param.slice(0, -2) + "=";
      for (var val in obj[param]){ _qs += val + ","; }
      _qs = _qs.slice(0, -1) + "&";
    }

    return _qs.slice(0, -1);

  })(checkedInputsObj);
  // -----------------------

  console.log(qs)
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form method="get" action="" class="productFilter">
  <input type="checkbox" name="firstArray[]" id="" value="0001">0001
  <input type="checkbox" name="firstArray[]" id="" value="0002">0002
  <input type="checkbox" name="secondArray[]" id="" value="0003">0003
  <input type="checkbox" name="secondArray[]" id="" value="0004">0004
  <input type="submit" name="submit" value="test">
</form>
JonSG
  • 4,650
  • 2
  • 19
  • 30
0
   var checked_first = []
    $("input[name='firstArray[]']:checked").each(function ()
    {
        checked_first.push($(this).val());
    });

var checked_second = []
    $("input[name='secondArray[]']:checked").each(function ()
    {
        checked_second.push($(this).val());
    });

Get the value of selected for each array

CiroRa
  • 462
  • 2
  • 12
0

One way of doing this with pure JS (no jQuery) could be like;

var    f = document.querySelector("form"),
    cba1 = Array.from(f.querySelectorAll("input[name='firstArray[]']")),
    cba2 = Array.from(f.querySelectorAll("input[name='secondArray[]']"));
f.onsubmit = function(e){
var fStr = cba1.reduce((p,c) => c.checked ? p.concat(c.value) : p,[]).join(","),
    sStr = cba2.reduce((p,c) => c.checked ? p.concat(c.value) : p,[]).join(","),
    qStr = !!fStr || !!sStr ? "?" : "";
!!fStr && (qStr+= "firstArray=" + fStr);
!!fStr && !!sStr && (qStr+="&");
!!sStr && (qStr+= "secondArray=" + sStr);
  console.log(qStr);
}
<form method="get" action="" class="productFilter">
    <input type="checkbox" name="firstArray[]" id="" value="0001">0001
    <input type="checkbox" name="firstArray[]" id="" value="0002">0002
    <input type="checkbox" name="secondArray[]" id="" value="0003">0003
    <input type="checkbox" name="secondArray[]" id="" value="0004">0004
    <input type="submit" name="submit" value="test">
</form>

This will be ok as many checkboxes as you have per firstArray or secondArray. I would recommend you to replace the arrows (reduce callbacks) with conventional functions if you would like this work on Safari and IE.

Redu
  • 19,106
  • 4
  • 44
  • 59