Is this a jQuery bug, or am I missing something? - php

I am using jquery-1.3.2 in an AJAX web application. I use the jQuery ajax $.post() method to submit requests to the server.
On the server I am using php to build an array and then json_encode the answer. Then on the client I use the callback function of the AJAX post method to process the response.
All works well until I use the $.post() method to send variables to the server. If I send variables to the server, the response I get back is [object Object] and therefore I am unable to parse it. I have a work around at the moment that when posting variables I request a HTML response and then I parse that.
So the code involved taken from my site is:
The Jax call:
$.post("inc/sendfeedback.php", {NAME: name,TYPE: type,EMAIL: email,COMMENT: comment}, function(data) {PostData(data);}, "json");
So the PostData code looks like this:
function ProcessData(data)
{
//alert(data);
var jo = eval("(" + data + ")");
if(jo.result == "true")
{
if(jo.data != "" && jo.element != "")
{
$(jo.element).html(jo.data);
}
}
SMessage(jo.error);
}
If I uncomment the above code the alert with have in it [object Object].
if I remove the Post variables from the call it works fine.
The server code look like this:
$arr = array ("result" => $result,"data" => $data,"error" => $error,"element" => $element);
echo(json_encode($arr));
Is this a bug with the jQuery library, I tried it with the 1.2 version however its was still present there? I also search the jQuery site and can not find anyone having this issue.
So I assume I am missing something. But what?

$.ajax({
url: "script.php",
global: false,
type: "POST",
data: {NAME: name,TYPE: type,EMAIL: email,COMMENT: comment},
dataType: "json",
contentType: "application/json",
success: function(data){
alert(data.result);
}
}
No need to eval, jQuery evals/parses it before calling the success callback.
eval = pure evil
http://docs.jquery.com/Ajax/jQuery.ajax#options

Because you are using an associative PHP array, json_encode will return a string representation of a Javascript Object and not a Javascript Array. However, you should still be able to process it in a similar fashion to an array:
for (var key in data)
{
var item = data[key];
}
I would strongly recommend you download Firefox+Firebug addon and use the console API for debugging/dumping what is being returned by the server.

I have since registered and now can't post comments into this thread without reputation and can not see any easy method to claim this question as mine.
Deviant, your suggestion of using the $.ajax() method worked. Reason it didnt work for me the first time was I submitted the post data as a JSON object when the server code was expecting POST data.
So I fixed my javascript to call the server script correctly and everything works exactly as it should.
So the conclusion is, the $.post() method has a bug in it. I have not tracked it down but line 3633 is were the post method makes the call. I started digging however have not yet found the issue.
I qualify this by the fact the $.ajax() to the same server script and the same javascript processes the response and it all works, use the $.post method and my script fails with the return even through the return object appears to be a valid JSON object.
Thanks for the help guys. Now to go and remove all my $.post calls for $.ajax calls.
The result of all this can be seen at www.pygames.net
Cheers
Shane
a.k.a FrogSkin

Related

Cross Origin Resource Sharing using AJAX methods and PHP

I just started to work on calls to a php file which is present in a different server. I am aware of CORS which is essential for cross domain requests. I have been trying to call this file through ajax methods refering to other websites and tutorials and I have seen discussions to find a solution but they are not working for me. Please help.
here is my calling method:
$.ajax({
type: "GET",
url: "http://cs-server.usc.edu:27952/ResponseProg.php?callback=?", //Relative or absolute path to response.php file
datatype: "jsonp",
data: dataInput,
jsonp:'jsoncallback',
crossDomain:true,
success: function(data)
{
JSONObj = jQuery.parseJSON(data);
contentProvider("#rtrn");
if(JSONObj.ack != "No results found")
{
var paginate=setPager(0);
$("#pgn").html(paginate);
}
},
error: function() {
$("#rtrn").html("Data not retrieved successfully");
}
});
Here is my PHP code snippet:
<?php
#code for data processing...
$rsltjson = json_encode($result,JSON_UNESCAPED_SLASHES);
echo $_GET['jsoncallback']."(".$rsltjson.");";
?>
I am trying to accomplish this by using JSONP. Should I have any headers?
Are there any errors in my code?....How can I accomplish this? dataInput is the serialized form of form data
The CORS way
You need to put the appropriate header in your php script and output only the JSON:
<?php
header('Access-Control-Allow-Origin: *');
// rest of the code
// output JSON only
echo $rsltjson;
?>
Then using a XMLHttpRequest/ajax call should retrieve the data just fine as JSON without resorting to JSONP.
Mozilla has plenty to read about it
The JSONP way
Since the whole point of JSONP is to bypass cross-domain restrictions, calling a JSONP resource with XMLHttpRequest/ajax, a method in which cross-domain security is fully applied (presumably), is completely useless.
JSONP works by injecting code directly into your page, calling a function that you defined, which is why a JSONP url takes an argument. Therefore, the correct way to call your JSONP url is this:
<script>
function myDataFunc(data) {
JSONObj = jQuery.parseJSON(data);
contentProvider("#rtrn");
if(JSONObj.ack != "No results found") {
var paginate=setPager(0);
$("#pgn").html(paginate);
}
}
</script>
<script src="http://cs-server.usc.edu:27952/ResponseProg.php?jsoncallback=myDataFunc"></script>
The JSONP url will return something that looks like this:
myDataFunc({"a":"fhsfg","b":"qfdgers","c":"difgij"});
Since it is included as a script, it will be executed directly in your page, calling the function myDataFunc() that you defined earlier.
Also note that your php file use the GET parameter jsoncallback while your javascript calls the url with the parameter callback, which would not work.
Finally, you use jQuery.parseJSON(), which produces this error from your code:
SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data
The reason can be found in the jQuery docs:
jQuery.parseJSON( json )
Description: Takes a well-formed JSON string and returns the resulting JavaScript value.
Passing in a malformed JSON string results in a JavaScript exception being thrown.
Your php script feeds your callback with a JSON object
{"a":"fhsfg","b":"qfdgers","c":"difgij"}
rather than a string representing a JSON object
'{"a":"fhsfg","b":"qfdgers","c":"difgij"}'
Note the surrounding quotes, which makes this data a string. We fix this in php by adding the quotes around the data:
echo $_GET['jsoncallback']."('".$rsltjson."');";
Obviously if your JSON data contains single quotes, you will have to escape them.

Sending information with AJAX and CodIgniter

Hey guys I am building an application in which I send input value from a text box via AJAX to a controller function and then return what I send back to the user (I am developing an instant search, this is a first step).
The AJAX links to the method fine however I am having problems returning the information. I receive no error messages, the problem is that the return string is BLANK.
I receive [you wrote ] rather than [you wrote WHATEVER I IN PUTTED ]
Any help greatly appreciated.
view_index.php
function search(){
var term = document.getElementById("mainsearch").value;
$.ajax({
type: "POST",
url: "<?php echo base_url('index.php/site/search/')?>",
data: term,
cache: false,
success: function(html){
alert("you wrote " + html);
}
});
controller_site.php
function search(){
$gotcha = $this->input->post('term');
return $gotcha;
}
The data: parameter accept a key : value json to pass to the POST, as the json array key will be your $_POST key
Try with this:
$.ajax({
type: "POST",
url: "<?php echo base_url('index.php/site/search/')?>",
data: {'term': term }
cache: false,
success: function(html){
alert("you wrote " + html);
}
});
You didn't send your data correctly, so PHP has nothing to process, and you end up sending back nothing:
data: term,
POST/GET requests MUST be in key=value format, and you're sending only the value portion. Try
data: {foo: term},
and then
$gotcha = $this->input->post('foo');
You need to change return to echo as AJAX response works on whatever echo from called function.
So, you can code like :
function search(){
$gotcha = $this->input->post('term');
echo $gotcha;
}
or
function search(){
echo = $this->input->post('term');
}
The responseText property returns the response as a string, and you can use it accordingly
It is generally a bad idea to return HTML from your controllers. Instead try to just manage data server-side wise and do all the frontend on the client side.
Now, for the error:
The success callback takes 3 parameters
You need to pass key-value pair in the data argument of the .ajax call
Make sure you handle errors on your controller appropriately because if something goes wrong you'll get an html document as a response from CodeIgniter and you'll spend a lot of time debugging javascript to find out that the error was actually server-side
1 the callback:
Your success callback function should look like this:
function (data, status, response) {
}
Where:
data is whatever you are echoing from your controller's method. You'll probably want JSON.
status Will tell you if the HTTP response message (e.g. "Not Found" is the status for a 404 code, "success" for a 200 code)
response is the jquery wrapped XmlHttpRequest object that gives you a handful information of the transaction, for example response.responseText would give you whatever you outputed from PHP, response.responseJSON would give you a JSON object if you echoed a json encoded object, etc.
Why should you care? Because those extra parameters will let you decide if something went wrong on your backend so you can handle the situation client-side not leaving the user wondering if you app just don't work. Worse, giving the infamous red cross on the status bar of the browser.
If you set the dataType parameter of the jQuery.ajax function then you can explicitly tell jQuery what kind of data you are expecting to be retrieved from the server on data parameter from your callback.
2 the sent data
As said, you need to either pass value-pairs or a URL encoded string. If you intend to use GET then you can pass the URL encoded string, but that means you have to have arguments on your CI function like:
function search($term)
And then CI automatically routes the incoming parameters. But since you want to do POST then you'll want to effectively get the values with $this->input->post("name")
If you have your input inside a form, or several fields that you need to send, then its easier to just serialize the form:
$.ajax("url", {
type : 'POST',
data : $('#form').serialize(),
dataType : 'json',
success : function(data, status, response) {} error : function(response, status error) {}});
3 handle errors
If you are relying on AJAX then make sure that you return some sort of error or warning so you can catch it client side:
function search() {
$term = $this->input->post("term")
if($term == FALSE) {
//return a 404 so that you can catch .error on jquery
} else {
echo $term;
}
}
Do a research on RESTFul apps. It'll help you a lot understanding that. this is a good starting point and although your question was not exactly related to this, it is a good practice to have separate layers on your application so that you just consume data from your backend, handle situations and then just react accordingly on the frontend, that is, you just use javascript to either send, receive and list data. If you are using CI or any other MVC framework then you should not really be generating HTML on your controllers, thats what the views are for.

simple jsonp not working with php server

I tried following some basic examples, and it is not working. I am not sure I completely understand jsonp, but I followed the basic tutorials and on an intuitive level, I can't see anything wrong. (Of course, I am missing something, hence the question).
JavaScript code:
postData = $(this).serialize();
console.log(postData);
$.ajax({
data: postData,
url: 'externaldomain.php',
dataType: 'jsonp',
success: function(data){
console.log(data);
alert('Your comment was successfully added');
},
error: function(){
console.log(data);
alert('There was an error adding your comment');
}
});
PHP code:
$tag = mysql_real_escape_string($_GET["callback"]);
The annoying part is that it is not even showing me an error to Google for.
Can anyone help out figuring the problem please?
Since you haven't posted your full or relevant PHP code I'm going to assume it looks like this
$tag = mysql_real_escape_string($_GET["callback"]);
echo $tag."(";
// print json here
echo ")"
I'm not really sure how jquery handles jsonp requests but what I used to do is add a new script tag to the DOM that looks like this
<script> function cb(json) { alert(json); } </script> // (I)
<script src="{url}?callback=cb"></script> // (II)
When (II) is loaded, and because we have a callback then the script that we are including in the DOM looks like this
cb({
// json goes here
})
which pretty much is like a function call to some function called cb that we are using. It is therefore natural to have an implementation of cb (which is in (I)). That implementation is similar to the success(data) function in jQuery's ajax. It is used to use and manipulate the json requested
However I noticed that you are doing a POST request along the ajax call with jsonp. Unfortuantely (according to this question How to make a jsonp POST request that specifies contentType with jQuery?) doing POST with JSONP is not feasable due to implementation pursposes.
You can't POST using JSONP... it simply doesn't work that way...
So you can usually only perform GET requests. You can NOT perform POST requests.
For details about how jsonp work look at this nice article. jsonp-how-does-it-work
For more clearification :
See Other SO question Link1 Link 2
But there is work around for that with some limitations look at this Using PUT/POST/DELETE with JSONP and jQuery. (for me nothing works at all)

POST data not appearing in CakePHP controller

I'm using AJAX on a knockout.js form to post some information that CakePHP should receive, however, Cake doesn't seem to find anything. Also, the alert isn't appearing despite a 200 status (OK) from the POST.
Here's the AJAX
$.ajax({
url: "/orders/finalize_payment",
type: "POST",
dataType: "json",
contentType: "json",
data: JSON.stringify({"customer": customer_id}),
success: function(){
alert("success");
}
});
Here's the corresponding action in the orders controller. Right now, I completely stripped it to just the bare minimum.
function finalize_payment($id = null){
$this->layout = false;
$this->autoRender = false;
if($this->request->is('post')){ //the user has submitted which status to view
print_r($this->request->data);
echo "test"; //just to make sure it's reaching this point
}
}
When I open up the network tab in chrome, it shows the request payload as
customer: 1
The POST shows as success, status 200. I checked the response headers and it just shows
array
(
)
test
Despite chrome showing a payload being sent, CakePHP isn't finding it apparently.
Update
I changed the request from AJAX to $.post and it worked. I still have no clue why
$.post("/orders/finalize_payment",{"customer_id":customer_id},function(data){
alert('success');
});
Don't encode post data as json
The code in the question won't appear in any php script, the reason is this:
contentType: "json"
It's not a form-url-encoded request, so e.g. the following code:
print_r($_POST);
print_r(file_get_contents('php://input'));
will output:
Array()
'{"customer":123}'
If you want to submit data as json, you'll need to read the raw request body:
$data = json_decode(file_get_contents('php://input'));
There might be times when that's desirable (api usage), but that isn't the normal way to use $.post.
The normal way
The normal way to submit data, is to let jQuery take care of encoding things for you:
$.ajax({
url: "/orders/finalize_payment",
type: "POST",
dataType: "json", // this is optional - indicates the expected response format
data: {"customer": customer_id},
success: function(){
alert("success");
}
});
This will submit the post data as application/x-www-form-urlencoded and be available as $this->request->data in the controller.
Why $.post works
I changed the request from AJAX to $.post and it worked. I still have no clue why
Implicitly with the updated code in the question you have:
removed the JSON.stringify call
changed from submitting json to submitting application/x-www-form-urlencoded
As such, it's not that $.post works and $.ajax didn't ($.post infact just calls $.ajax) - it's that the parameters for the resultant $.ajax call are correct with the syntax in the question.
As you're using CakePHP you may find adding RequestHandler to your components fixes the problem.
public $components = array([snip], 'RequestHandler');
Doing this allowed me to transparently access JSON posted data using $this->request->data. The other answer's advice to not encode POST data as JSON becomes a bit awkward, given that certain JS frameworks, such as Angular, post JSON as default.
Using raw data and json you can use:
$data = $this->request->input('json_decode');
**Data is an object now, not an array.
Then you can use:
$this->MyModel->save($data).
Nicely formatted question :)
I'm pretty sure I have the answer, though I could be wrong... Basically, $this->request is an object in Cake, and $this->request->data is a variable/array that's a property of the object.
The data you're sending to Cake is going straight into the object (if this is even possible), not into the data array. This is why when Cake generates forms using the HtmlHelper, the names are, for example data[User][username].
I think, if you put JSON.stringify({"customer": customer_id}) into a 'data' array and send that, it should work.
Have a look at this post. You're data string probably isn't correct. Therefore CakePHP might not be able to put it in $this->request->data.
Use print_r($this->request->params);
function finalize_payment($id = null){
$this->layout = false;
$this->autoRender = false;
if($this->request->is('post')){ view
print_r($this->request->params);
} }

JSON response is null, but the URL is echoing correctly

I have a form being AJAX'd in by jQuery on a page with multiple forms. I'm performing the following function, which is a wrapper for the $.ajax function:
function do_json_get(uri){
var ret = '';
var url = AJAX_URL + uri;
$.ajax({
type: 'GET',
url: url,
async: false,
success: function(data) {
ret = data.html;
},
dataType: 'json'
});
return ret;
}
When I go to the AJAX server directly (which is rendering the form in PHP), I get the raw JSON response - so I know the server is outputting to the browser, and the AJAX server is doing other things like setting the proper cookies, so I know that the connection is good (I get a 200 response code). Yet the data object is coming back null.
Here's a guess. If you're serving the page from the file system, Firefox (and I think Chrome) will see it as originating from a different domain. You'll get the 200 response, but no data.
Try Safari, or maybe give jsonp a shot in place of json.
EDIT:
Since you're getting the data from a different domain, it won't work. I think it is not allowed by the XMLHTTPRequest.
Oh boy. This question again.
AJAX: Asynchronous JavaScript And XML*. Asynchronous. Asynchronous. Asynchronous.
Your function, do_json_get() returns ret before the success handler function in the AJAX call executes. The order of operation is not proceeding, here, from top to bottom. In other words, you just can't do it that way.
Because of its asynchronous nature, AJAX operates on callbacks, not return values. You need to change your paradigm. The success handler function needs to do whatever is required with data.html itself, or pass it off to another function.
* Yes, I know the XML part of the original acronym is largely vestigial these days

Categories