Skip to main content

Bug Tracker

Side navigation

#2207 closed feature (wontfix)

Opened January 21, 2008 11:55PM UTC

Closed July 28, 2008 06:14PM UTC

Last modified March 15, 2012 10:09AM UTC

serializeArray should treat elements with [braces] as arrays

Reported by: dubhunter Owned by: flesler
Priority: major Milestone: 1.3
Component: ajax Version: 1.2.6
Keywords: serialize array Cc:
Blocked by: Blocking:
Description

serializeArray should treat elements with [braces] as arrays.

I understand that serialize (which returns a get query string) needs the [] braces left by serializeArray, but since on the receiving end, the query string would be parsed back into an array....shouldn't serializeArray do the same?

Could it be that $().val() never returns type of array?

I've tried with checkboxes, selects, select multiples... and I cannot get it to figure things out.

Attachments (0)
Change History (10)

Changed January 25, 2008 10:59PM UTC by davidserduke comment:1

type: bugfeature

Changed May 11, 2008 11:30PM UTC by flesler comment:2

owner: → flesler
status: newassigned

This sounds like a fun feature, let me handle :)

Changed May 14, 2008 10:15PM UTC by flesler comment:3

OK, I think I missunderstood this, I thought it was something like #2726.

But seems it isn't.

Could you please rephrase your ticket a bit ?

Thanks

Changed June 10, 2008 08:46PM UTC by ygirouard comment:4

I see what he means: If you have multiple inputs with names like "check[1]", "check[2]", "check[3]", etc...

The $.serializeArray() function should convert those inputs into an array of "check" as it would be done by server-side parser when the data is passed via POST or GET...

But instead it creates an array like this:

array(
 0 => array("check[1]" => value1),
 1 => array("check[2]" => value2),
 2 => array("check[3]" => value3)
)

instead of...

array(
 0 => array("check" =>  array("1" => value1, "2" => value2, "3" => value3))
)

... which is what passing inputs that have braces in their names would become after being passed with POST or GET once they get parsed by the server.

I believe it does fall within the same subject as the closed ticket you referenced however.

Changed July 01, 2008 03:16AM UTC by flesler comment:5

component: coreajax
milestone: 1.2.31.3

Changed July 22, 2008 04:29PM UTC by flesler comment:6

resolution: → worksforme
status: assignedclosed

This does work for me, see #2377.

This html:

<form>
	<input type="text" name="name[0]" value="aaaa" />
	<input type="text" name="name[1]" value="bbbb" />
	<input type="text" name="name[2]" value="cccc" />
</form>

With this PHP:

<?php
	print_r($_POST);
?>

I ran this code:

$.ajax({ url:'foo.php', data:$('form').serialize(), type:'post'});

And the response was:

Array(
    [name] => Array(
      [0] => aaaa
      [1] => bbbb
      [2] => cccc
    )
)

Tried this with Firefox 2, both POST and GET.

Do reopen this with a concise test case that reproduces the error.

Changed July 22, 2008 09:31PM UTC by dubhunter comment:7

resolution: worksforme
status: closedreopened

OK, this took me a while to remember what is going on.

You are right, your example works perfectly...but only because there is an extra step.

When the serializeArray() return is passed as the data arg for $.ajax();, it is then passed through $.param(); which does the dirty work. This is fine when always using it for form submissions, but what I am after is just the serializedArray, not a array of strings to be complied into a get string.

The problem is on the client side, not the PHP side. Except it does become a PHP problem if I am passing data to the server without using $.ajax(); or $.param();

My Solution to this problem has been to create a method called $.serializeAssoc(); It will recursively serialize heterogeneous form arrays into a neat array like package. (I say array like, since JS will not support associative arrays, but objects work almost as well.)

I have attached my markup, js, php output, and my extension file (includes logging function and $.serializeAssoc()). I did not inlcude the debug output, because its hard to copy from firebug.

ygirouard is right though on the format of the JS object returned by $.serializeArray();

Here is my markup:


	<form name="jquery" id="jquery" action="/index/jqueryPost" method="post">
		<input type="checkbox" name="check[]" id="check0" value="aaaa" />
		<input type="checkbox" name="check[]" id="check1" value="bbbb" />
		<input type="checkbox" name="check[]" id="check2" value="cccc" />
		<input type="submit" name="button" id="button" value="submit" />
	</form>

Here is the JS:

$(function (){
	$('form :submit').click(function (e){
		e.preventDefault();
		var f = $(this).parents('form').get(0);

		$.log(f.action);

		var data = $(f).find(':input').serialize();
		data.fun = 'serialize';
		$.log(data);
		$.ajax({url: f.action, data: data, type: 'post', success: function (data){$.log(data);}});

		var data = $(f).find(':input').serializeArray();
		data.fun = 'serializeArray';
		$.log(data);
		$.ajax({url: f.action, data: data, type: 'post', success: function (data){$.log(data);}});

		var data = $(f).find(':input').serializeAssoc();
		data.fun = 'serializeAssoc';
		$.log(data);
		$.ajax({url: f.action, data: data, type: 'post', success: function (data){$.log(data);}});
	}).addClass("formBound");
});

And the responses:

Array
(
    [check] => Array
        (
            [0] => aaaa
            [1] => bbbb
            [2] => cccc
        )

)
Array
(
    [check] => Array
        (
            [0] => aaaa
            [1] => bbbb
            [2] => cccc
        )

)
Array
(
    [check] => Array
        (
            [0] => aaaa
            [1] => bbbb
            [2] => cccc
        )
    [fun] => serializeAssoc
)

Here is my JQ Lib file (jquery.ext.js):

(function($){
	$.extend({
		cssFile: function (f, m){
			$('<link>')
				.attr('href', f)
				.attr('type', 'text/css')
				.attr('rel', 'stylesheet')
				.attr('media', m || 'screen')
				.appendTo('head');
		},
		isArray: function (arr){
			if (typeof arr == 'object'){
				if (arr.constructor == Array){
					return true;
				}
			}
			return false;
		},
		arrayMerge: function (){
			var a = {};
			var n = 0;
			var argv = $.arrayMerge.arguments;
			for (var i = 0; i < argv.length; i++){
				if ($.isArray(argv[i])){
					for (var j = 0; j < argv[i].length; j++){
						a[n++] = argv[i][j];
					}
					a = $.makeArray(a);
				} else {
					for (var k in argv[i]){
						if (isNaN(k)){
							var v = argv[i][k];
							if (typeof v == 'object' && a[k]){
								v = $.arrayMerge(a[k], v);
							}
							a[k] = v;
						} else {
							a[n++] = argv[i][k];
						}
					}
				}
			}
			return a;
		},
		count: function (arr){
			if ($.isArray(arr)){
				return arr.length;
			} else {
				var n = 0;
				for (var k in arr){
					if (!isNaN(k)){
						n++;
					}
				}
				return n;
			}
		},
		log: function (msg){
			if (window.console)
				console.log(msg);
			else
				alert(msg);
		}
	});
	$.fn.extend({
		serializeAssoc: function (){
			var o = {
				aa: {},
				add: function (name, value){
					var tmp = name.match(/^(.*)\\[([^\\]]*)\\]$/);
					if (tmp){
						var v = {};
						if (tmp[2])
							v[tmp[2]] = value;
						else
							v[$.count(v)] = value;
						this.add(tmp[1], v);
					}
					else if (typeof value == 'object'){
						if (typeof this.aa[name] != 'object'){
							this.aa[name] = {};
						}
						this.aa[name] = $.arrayMerge(this.aa[name], value);
					}
					else {
						this.aa[name] = value;
					}
				}
			};
			var a = $(this).serializeArray();
			for (var i = 0; i < a.length; i++){
				o.add(a[i].name, a[i].value);
			}
			return o.aa;
		}
	});
})(jQuery);

Changed July 23, 2008 03:50PM UTC by flesler comment:8

need: ReviewTest Case
version: 1.2.21.2.6

Ok, I see your function...

Now, both serialize() and serializeArray() are meant for server side posting.

The way the array is serialized by param() is perfectly understood by the servers.

If you need a different serialization, for client side, you should indeed write your own.

Unless you can show a concrete situation (with a test case) where this is actually needed for ajax requests, this won't be taken into account.

I'll leave this open for now, please reply.

Changed July 23, 2008 07:51PM UTC by dubhunter comment:9

I guess I just see a lot of value in the ability to work with the data structure before its sent to the server or not to send it to the server at all. This is essentially why I originally list the component to be the "core" and not "ajax" because I agree that that functionality works perfectly.

My dream scenario would be for serializeArray() to return the proper data structure and then have param() take care of the rest when using it in an ajax context. Otherwise why even expose serializeArray(), when serialize() does everything you need for server-side processing.

I am personally fine with using my own function, but I just see value in this for other people.

While you are at it...any chance on getting any of my other methods into the core? cssFile(), isArray(), arrayMerge(), count(), log()???

Changed July 28, 2008 06:14PM UTC by flesler comment:10

resolution: → wontfix
status: reopenedclosed

The answer is always the same, if you provide a test case where any of these functions help improve perfomance or reduce code size, they will be added.

If they're just useful for the common user, but not for the core, then no.

They can always be put into a plugin.

My opinion:

cssFile: it's cool but has no use for the core.

isArray: we just use obj.constructor == Array.

ArrayMerge: Seems like a special case of $.extend. We use that method and for now, no complaints.

console & log: definitely useful, but not for the core.

Don't get me wrong, I like your code, but we're really cautious about new features. That's how we keep the filesize low.

Cheers