0

I have hidden inputs which, through the name attribute, represent an array. I need to be able to iterate over each group.

My technique is to iterate through all found fields (noting their name identifier and value) and push into an array which I can then iterate over. I am able to select and find these inputs correctly, although ideally I would be able to fetch them all as a single array.

It may not necessarily be known how many groups there are.

The code below does not work because I am only left with the final construct (group) which is represented in multiple arrays.

<input type="hidden" data-type="item1" name="group[0][item1]" value="">
<input type="hidden" data-type="item2" name="group[0][item2]" value="">
<input type="hidden" data-type="item3" name="group[0][item3]" value="">

<input type="hidden" data-type="item1" name="group[1][item1]" value="">
<input type="hidden" data-type="item2" name="group[1][item2]" value="">
<input type="hidden" data-type="item3" name="group[1][item3]" value=">

<input type="hidden" data-type="item1" name="group[2][item1]" value="">
<input type="hidden" data-type="item2" name="group[2][item2]" value="">
<input type="hidden" data-type="item3" name="group[2][item3]" value="">
$(function () {
    var i = 0;
    while ($(this).find('input[name^=\'group[' + i + '\']').length) {
        var arr = [];
        var condition = $(this).find('input[name^=\'group[' + i + '\']');
        $.each(condition, function () {
            var type = $(this).attr('data-type');
            var val = $(this).val();
            arr.push({
                [i]: {
                    [type]: val
                }
            });
        });
        i++;
    }
});

2 Answers2

0

You can use this serialize function taken from https://stackoverflow.com/a/12370626/1175966 to generate an object.

If you need this in array it can be easily converted and mapped using Object.values() or Object.entries()

const data = $('.hidden-group input:hidden').serializeJSON();
console.log(data)
.as-console-wrapper {max-height: 100%!important;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="hidden-group">
  <input type="hidden" data-type="item1" name="group[0][item1]" value="item1-0">
  <input type="hidden" data-type="item2" name="group[0][item2]" value="item2-0">
  <input type="hidden" data-type="item3" name="group[0][item3]" value="item3-0">
</div>

<div class="hidden-group">
  <input type="hidden" data-type="item1" name="group[1][item1]" value="item1-1">
  <input type="hidden" data-type="item2" name="group[1][item2]" value="item2-2">
  <input type="hidden" data-type="item3" name="group[1][item3]" value="item3-2">
</div>

<div class="hidden-group">
  <input type="hidden" data-type="item1" name="group[2][item1]" value="item1=2">
  <input type="hidden" data-type="item2" name="group[2][item2]" value="item2-2">
  <input type="hidden" data-type="item3" name="group[2][item3]" value="item3-2">
</div>

<script>
jQuery.fn.serializeJSON=function() {
  var json = {};
  jQuery.map(jQuery(this).serializeArray(), function(n, i) {
    var _ = n.name.indexOf('[');
    if (_ > -1) {
      var o = json;
      var _name = n.name.replace(/\]/gi, '').split('[');
      //console.log('_name', _name)
      for (var i=0, len=_name.length; i<len; i++) {
        if (i == len-1) {
          if (o[_name[i]]) {
            if (typeof o[_name[i]] == 'string') {
              o[_name[i]] = [o[_name[i]]];
            }
            o[_name[i]].push(n.value);
          }
          else o[_name[i]] = n.value || '';
        }
        else o = o[_name[i]] = o[_name[i]] || {};
      }
    }
    else {
      if (json[n.name] !== undefined) {
        if (!json[n.name].push) {
          json[n.name] = [json[n.name]];
        }
        json[n.name].push(n.value || '');
      }
      else json[n.name] = n.value || '';      
    }
  });
  return json;
};

</script>
charlietfl
  • 170,828
  • 13
  • 121
  • 150
0

I'm not sure if you want a 9-element array, which is what it sounds like you're asking for, each of a single property, or if you're looking for a 3 element array, each of three properties. It seems like the latter would be a lot more useful, but it sounds like you're asking for the former.

$(function () {
    let output1 = []; //prepare output variables
    let output2 = []; //prepare output variables
    var i = 0;
    while ($(this).find('input[name^=\'group[' + i + '\']').length) {
        var arr = [];
        output2[i] = {}; // this prepares the output variable to collect properties 
        var condition = $(this).find('input[name^=\'group[' + i + '\']');
        $.each(condition, function () {
            var type = $(this).attr('data-type');
            var val = $(this).val();
            arr.push({
                [i]: {
                    [type]: val
                }
            });
            output2[i] = {...output2[i],[type]:val} //This appends the properties
        });
        i++;
        output1 = output1.concat(arr); // this is to add everything to one array
    }
    console.log(output1); //output of the long array of two-layer objects.
    console.log(output2); //output of the short array of flattened objects.
});

If you run that, mostly unchanged from your code, you can compare the outputs to see which is what you're looking for. I commented everything that I added.

Sam Hughes
  • 665
  • 8
  • 10