PDA

View Full Version : Ext.Ajax.request - params property behavior



Nullity
13 Jan 2011, 11:45 AM
I've been away from using Ext for a few years, and started using it again with the latest version (3.3.1) for a new project, so my Ext skills and knowledge are pretty rusty.

I'm trying to do a simple ajax call, but for some reason, I cannot seem to send arrays through to the server side.

Ext.Ajax.request({
url: 'file.php',
method: 'POST',
success: successFn,
failure: failFn,
params: {test: ['foo', 'bar']}
});

The PHP on the server is doing nothing but printing the $_POST variable so I can see what's getting to the server:

<? print_r($_POST); ?>
However, no matter how many objects I have in the array, only the last item seems to make it to the server:

Array
(
[test] => bar
)

After searching the forums, I also tried replacing the "params" option with "jsonData", but then nothing prints out from the PHP side:

Array
(
)

I also tried wrapping the "params"/"jsonData" data with Ext.encode, but that didn't work either. I am currently using jQuery to work around this issue, but that should be unnecessary. I don't want to load the whole jQuery library just to do this one task.

This should be pretty simple, what am I missing?

darthwes
13 Jan 2011, 1:25 PM
Why not just concatonate your array? The problem is with Ext.data.Connection encoding the params, javascript doesn't allow you to define an object with the same property with different values
{
x: 12,
x: 14
} is basically the object that is being created and urlencoded by Connection when you define an array in your params. Which is why you only ever see the last one you set, the other times are being overwritten. If you use a dataWriter-enabled store, you can set listful on the dataWriter to get a workaround.

Nullity
13 Jan 2011, 2:01 PM
Thank you for the reply, I appreciate your input.

I hope your suggestions are not the only way, as that would cause a lot of extraneous code. I like to keep things neat. :)

Anyway, until/unless I figure out a different way, I'm going to continue using jQuery. I'd rather take the extra time to load that code into memory, then write a bunch of workarounds. jQuery can handle sending the exact same data without problems, perhaps they should consider changing/updating the way Ext encodes the params to mimic this.

Personally, I'd consider this issue a bug, even if that's the way it was "designed". It seems like such a simple task.

darthwes
13 Jan 2011, 2:10 PM
Actually, it is being encoded twice so that the XHR POST header looks like

test:foo
test:bar

which is somewhat correct. Sounds like PHP is the source of the problems, how is jQuery assisting you, is it passing an actual array?

Nullity
13 Jan 2011, 2:16 PM
jQuery encodes it as such:

test[]:foo
test[]:bar

Which then gets rebuilt into an array on the server side.

darthwes
13 Jan 2011, 2:22 PM
So just do


params: {'test[]': ['foo', 'bar']}

Nullity
13 Jan 2011, 2:24 PM
Talking this out gave me an idea. I tried to pass the following to the params option:

Ext.urlEncode({test: ['foo', 'bar']})
I was almost sure this would produce "test[]=foo&test[]=bar", but it did not and instead returned "test=foo&test=bar", which is the same as the other method (this can be easily tested in the firebug console).

I'm thinking this has to be wrong. Url encoding an array certainly should have produced a string resembling what I thought would happen above.

Nullity
13 Jan 2011, 2:29 PM
So just do


params: {'test[]': ['foo', 'bar']}

That's a good suggestion, and while it works great for this small test data, it's not practical for a large dataset, particularly one that is dynamically generated. I'm working with a fairly large object (containing arrays) that I need to pass to the server. I only broke it down to try and figure out why it was not working how I expected it to.

Implementing your suggestion with my actual data just isn't feasible.

Good suggestion though. :)

darthwes
13 Jan 2011, 6:51 PM
params = function (p) {
var x = {};
for (var mem in p) {
if (!Ext.isArray(p[mem])) {
x[mem] = p[mem];
} else if (!Ext.isFunction(p[mem])) {
x[mem + '[]'] = p[mem];
}
}
return x;
}(params);


would seem to work, no?

Nullity
14 Jan 2011, 7:06 AM
Yes, it does work for our simple test data, but it fails if there are nested objects/arrays. I also know I could modify your function to handle this, but this is just an ugly/"hacky" solution.

Please don't take that the wrong way, I appreciate you taking the time to try and help me, I don't mean it personally. I just don't like the idea of writing/using wasteful code.

I have decided to stick with jQuery as a temporary solution, until I can find the time to "fix" Ext, and possibly submit a patch. In my opinion, this is certainly not the way this should behave and I would consider it a bug.

mschwartz
14 Jan 2011, 7:26 AM
params: { test: Ext.encode([ 'foo', 'bar']) }

On the server side (PHP example):
$test = json_decode($_REQUEST['test']);

And:
$test[0]==='foo' (TRUE)
$test[1]==='bar' (TRUE)

darthwes
14 Jan 2011, 7:37 AM
ty

Nullity
14 Jan 2011, 8:32 AM
params: { test: Ext.encode([ 'foo', 'bar']) }

On the server side (PHP example):
$test = json_decode($_REQUEST['test']);

And:
$test[0]==='foo' (TRUE)
$test[1]==='bar' (TRUE)
Thank you, but that does not work.


Ext.Ajax.request({
url: 'file.php',
method: 'POST',
success: successFn,
failure: failFn,
params: {test: Ext.encode(['foo', 'bar'])}
});
... with the following PHP code:

$test = json_decode($_REQUEST['test']);
print_r($test);

... returns nothing. Completely blank.

Even if it did work, we'd be back to the same issue where it's just not acceptable to me to create a function to loop through a large set of data to format it in the manner you used in your example. Ext should be able to encode a properly formatted javascript/json object so that is comes out correctly on the other side without having to first obfuscate the data into an incorrect structure.

It just needs fixed.

mschwartz
14 Jan 2011, 8:35 AM
Thank you, but that does not work.


Ext.Ajax.request({
url: 'file.php',
method: 'POST',
success: successFn,
failure: failFn,
params: {test: Ext.encode(['foo', 'bar'])}
});
... with the following PHP code:

$test = json_decode($_REQUEST['test']);
print_r($test);

... returns nothing. Completely blank.

Even if it did work, we'd be back to the same issue where it's just not acceptable to me to create a function to loop through a large set of data to format it in the manner you used in your example. Ext should be able to encode a properly formatted javascript/json object so that is comes out correctly on the other side without having to first obfuscate the data into an incorrect structure.

It just needs fixed.

The code does work, I've done that sort of thing a bazillion times.

Take a look at the net tab with firebug and see it's sending what you think.

Maybe try $_POST instead of $_REQUEST, maybe your version of PHP is configured different than mine...

If you have an arbitrarily complex JavaScript Object named "someComplexObject" then you can do this:

params: { test: Ext.encode(someComplexObject) }

Nullity
14 Jan 2011, 8:51 AM
Firebug shows that it is sending:

test ["foo","bar"]
I also tried with $_POST, but with the same results. I suppose it's possible something is configured differently on my server from yours, but that still doesn't change my ultimate point. I don't find it acceptable to be required to alter correctly formatted data. Jumping through these kinds of hoops should be unnecessary.


params: {test: ['foo', 'bar']}

should just work.

mschwartz
14 Jan 2011, 8:52 AM
Ext has no idea of what the server side is.

Formatting a post string like:

test[]=foo&test[]=bar

would work for PHP but not for a Java server (perhaps, just guessing) or ASP.

mschwartz
14 Jan 2011, 8:55 AM
Firebug shows that it is sending:

test ["foo","bar"]
I also tried with $_POST, but with the same results. I suppose it's possible something is configured differently on my server from yours, but that still doesn't change my ultimate point. I don't find it acceptable to be required to alter correctly formatted data. Jumping through these kinds of hoops should be unnecessary.


params: {test: ['foo', 'bar']}

should just work.

Makes no sense.

If you do

params: { test: 'this is a string' }

does the print_r work on the server side?

Ext.encode() in all the params examples I've posted returns a string. if one works, the other should too.

Nullity
14 Jan 2011, 9:20 AM
Ext has no idea of what the server side is.

Formatting a post string like:

test[]=foo&test[]=bar

would work for PHP but not for a Java server (perhaps, just guessing) or ASP.
That's a good point, I didn't even consider that.


Makes no sense.

If you do

params: { test: 'this is a string' }

does the print_r work on the server side?

Ext.encode() in all the params examples I've posted returns a string. if one works, the other should too.

I already thought of that. I tried it multiple ways, just in case:


$test = json_decode($_REQUEST['test']);
print_r($test);

$test = json_decode($_REQUEST['test']);
print $test;

$test = json_decode($_REQUEST);
print_r($test);

$test = json_decode($_REQUEST);
print $test;

None worked (and also tried all combinations with $_POST instead of $_REQUEST). I'll admit that it seems a bit odd, I would think at least one of them should return something. Anyway, I'm going to stick with jQuery for the time being. I feel more comfortable with that solution than jumping through hoops (though having to use jQuery is still a hoop, it's a much cleaner and easier solution).

I may try to write an override to urlEncode when I get some time.

mschwartz
14 Jan 2011, 9:21 AM
What happens if you print_r($_REQUEST['test']) ?

Nullity
14 Jan 2011, 9:52 AM
What happens if you print_r($_REQUEST['test']) ?

It returns

[\"foo\",\"bar\"][]

mschwartz
14 Jan 2011, 10:52 AM
Your server has magic_quotes turned on. TURN THOSE OFF!


It's in php.ini

Nullity
14 Jan 2011, 11:43 AM
Your server has magic_quotes turned on. TURN THOSE OFF!


It's in php.ini

Thanks, that did it. I didn't know that was turned on by default.

In addition, I was able to slightly tweak the PHP code and now the script works with my actual data. That magic_quotes was really messing with me.

Thanks again!

mschwartz
14 Jan 2011, 11:45 AM
The backslashes in your $_REQUEST content was a clue :)

It's one of the most horrid features of PHP.

If you're on a hosting environment and can't control your php.ini, you have to detect they're turned on and do a stripslashes() on the $_REQUEST value.

ICK