codephobia
codephobia

Reputation: 1590

Jquery map complex array from inputs

I need to map an array of inputs to pass via an ajax call. Inputs look like this:

<input type="hidden" name="sizes[0][id]" value="0" class="sizes">
<input type="hidden" name="sizes[0][name]" value="Small" class="sizes">
<input type="hidden" name="sizes[1][id]" value="1" class="sizes">
<input type="hidden" name="sizes[1][name]" value="Medium" class="sizes">
<input type="hidden" name="sizes[2][id]" value="2" class="sizes">
<input type="hidden" name="sizes[2][name]" value="Large" class="sizes">

I'm trying to map it like the following, but it is not working as it doesn't grab the id or name field.

var sizes = $('input.sizes').map(function(){ return $(this).val(); }).get();

Maybe this needs to be recursive somehow?

Edit: The output needs to work with the following code:

$.ajax({
  type  : "POST",
  cache : false,
  data  : {
    sizes: sizes,
    ...
  },
  url   : 'http://what.does.the.fox/say',
  dataType : 'json',
  ...
});

Another update: This should create an array of objects that resemble the input name tag. ie:

var sizes = [
  { id: 0, name: 'Small' },
  { id: 1, name: 'Medium' },
  { id: 2, name: 'Large' }
];

Upvotes: 1

Views: 729

Answers (3)

codephobia
codephobia

Reputation: 1590

I found code online that is able to do this as I want it. This also makes it completely dynamic so it doesn't matter what fields are named, or how many there are. Here is the code I found here in a comment:

(function(jQuery){

 jQuery.fn.MytoJson = function(options) {

    options = jQuery.extend({}, options);

    var self = this,
        json = {},
        push_counters = {},
        patterns = {
            "validate": /^[a-zA-Z][a-zA-Z0-9_]*(?:\[(?:\d*|[a-zA-Z0-9_]+)\])*$/,
            "key":      /[a-zA-Z0-9_]+|(?=\[\])/g,
            "push":     /^$/,
            "fixed":    /^\d+$/,
            "named":    /^[a-zA-Z0-9_]+$/
        };


    this.build = function(base, key, value){
        base[key] = value;
        return base;
    };

    this.push_counter = function(key){
        if(push_counters[key] === undefined){
            push_counters[key] = 0;
        }
        return push_counters[key]++;
    };

    jQuery.each(jQuery(this).serializeArray(), function(){

        // skip invalid keys
        if(!patterns.validate.test(this.name)){
            return;
        }

        var k,
            keys = this.name.match(patterns.key),
            merge = this.value,
            reverse_key = this.name;

        while((k = keys.pop()) !== undefined){

            // adjust reverse_key
            reverse_key = reverse_key.replace(new RegExp("\\[" + k + "\\]$"), '');

            // push
            if(k.match(patterns.push)){
                merge = self.build([], self.push_counter(reverse_key), merge);
            }

            // fixed
            else if(k.match(patterns.fixed)){
                merge = self.build([], k, merge);
            }

            // named
            else if(k.match(patterns.named)){
                merge = self.build({}, k, merge);
            }
        }

        json = jQuery.extend(true, json, merge);
    });


    return json;
 }

})(jQuery);

Upvotes: 1

Jay Blanchard
Jay Blanchard

Reputation: 34416

EDITED: This is what you want - http://jsfiddle.net/jayblanchard/2F5vD/3/ (Now new and improved with proper quotes!)

var dataString = '';
dataString += '[';
var inputLength = $('input.sizes').length;
$('input.sizes').each(function(index) {
    if( $(this).is('[name$="[id]"]') ) {
        dataString += '\'' + $(this).val() + '\':';
        dataString += '{ id:' + $(this).val() + ',';
    } else if( $(this).is('[name$="[name]"]') && 0 != inputLength -1 ) {
        dataString += ' name:\'' + $(this).val() + '\'},';
    } else {
        dataString += ' name:\'' + $(this).val() + '\'}';
    }
    inputLength--;
});
dataString += ']';

It produces the following output (that will now pass JSLint)-

[{"0":{ "id":"0", "name":"Small"},"1":{ "id":"1", "name":"Medium"},"2":{ "id":"2", "name":"Large"}}]

This pretty much used brute force methodology to get a JSON string and there may be some much easier ways to do this. this can easily be ported to a function that can be called over and over. I hope that it helps.

Upvotes: 0

Fresheyeball
Fresheyeball

Reputation: 30015

DEMO

var sizes = $('input.sizes').map(function(){ 
    return { id   : this.id,
             name : this.name,
             val  : $(this).val()
            }; 
}).get();

Note for jQuery-o-philes: in this case this.id is the same as $(this).attr('id'), its just that we don't need jQuery to get the id if we already have the element. Same thing with this.name.

Upvotes: 0

Related Questions