cakephp, jquery, .ajax(), dataType: json - php

is it possible to be able to do without a view for a cakephp controller function? i am trying to have my server return a datatype that is not a string - but an array
my controller function :
function test() {
$this->layout = 'plain';
$task['Numbers']['uno'] = 'mooo';
$task['Numbers']['dos'] = 'says the cow';
$result = json_encode($task);
$this->set('result', $result);
}
my view file test.ctp
echo $result;
my jquery:
$('#test').live('click', test);
function test() {
var data = $('#form').serialize();
$.ajax({
type: "post",
url: "/controller/test",
data: data,
dataType: 'json',
success: function(response){
alert(response.Numbers.uno);
}
});
}
clicking on the html element marked test doesn't give me anything. however if i take out
dataType: 'json',
and change alert(response.Numbers.uno); to
alert(response);
in my jquery - i get an alert: the json encoded data but as a string (alert(typeof response);)
does anyone have any idea what might be happening?

First, to answer your question, yes you can do without a view (and this is a good case for doing so). In your controller action (test, in this case), just set $this->autoRender = false;. That's what I usually do and just echo out the encoded JSON string in the controller itself. Less clutter that way.
The next thing that I'd look at are your debug settings in config.php. If not set to 0, there's a very good chance that this is your problem. Your echo statement may be echoing the JSON-formatted string, but appending debug output to it. In the method, just include Configure::write ( 'debug', 0 ). This will disable debug only for the current request. I usually do this in my AppController actually:
if ( $this->RequestHandler->isAjax() ) {
Configure::write ( 'debug', 0 );
}
I'd engage a tool like Firebug and see what's happening to your ajax request. It will monitor those requests and provide the request and response headers for you to inspect. That may help. If the latter is the problem, then Firebug would have shown you that in the response headers.

I agree with Rob, except with setting your debug in the app controller. It gets a little annoying to me because you have to set the debug level in the app controller every time you want to debug something for a specific function. I write my handler out like this in the controller i am working in.
Configure::write('debug', 0);
$this->autoRender = false;
Also I agree with the use of firebug. With firebug all you have to do is open firebug, click on console, and then run your test. This will tell you what you are doing with your jquery and give you the results.

Check out the cakePHP book on Request Handling:
http://book.cakephp.org/view/174/Request-Handling
CakePHP has some built in functionality to handle controller methods that return json.

You have to transform the data before use it.
See this answer:
jQuery ajax request with json response, how to?
you have to use the
var json = $.parseJSON(response);
alert(json.Numbers.uno);

I just use
die(json_encode(array('success' => true, 'result' => $result)));
at the end of the called controller method and it works for me.

Related

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.

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);
} }

Php script returns json, but I am getting parseerror

i know that there was similar questions, but i would like to get some clarification here.
With following Ajax setup:
$.ajaxSetup({
cache: true,
dataType: 'json',
error: function(xhr, status, error){
console.log(status);
},
timeout: 60000, //Timeout of 60s
type: 'POST',
url: 'test.php'
}); //Close $.ajaxSetup()
$('#openTest').bind('click', function(){
$.ajax({
data: {val: "Hello", val2: "Hello2"},
success: function(response){
console.log('complete');
console.log(response);
}
});
When 'test.php' is:
<?php
$return= array ('one'=>'one1', 'two'=>'two1');
return json_encode($return);
?>
I am getting parseerror. But when I replace 'return' with an 'echo', it works fine.
<?php
$return= array ('one'=>'one1', 'two'=>'two1');
echo json_encode($return);
?>
I will be retrieving much more complex data via this $.ajax calls, and I was expecting 'return' to works, 'echo' doesn't seems to me like good solution.
So, what are you suggesting? Is there something wrong with the Ajax setup, or call, so 'return' doesn't work, and is 'echo' a good solution?
Thanks.
return returns data to the caller of the function and since you are not in a function you cannot use return.
echo prints the data. So echo is the way to go.
when you do a return in php, it is not printed. When you do an echo, it gets printed.
Nothing is wrong with php or Ajax, it is just the context which is wrong.
Sinply put, use return when u need to catch the returned data and maybe process it. Best case for using return is in functions.
Use echo when you need to print something directly.
Here in this case using an echo and exit is what i recommend.
Return is used in functions to get the data back and use it in some fashion in your PHP. Echo is used for ajax calls because your PHP code will output the data to whatever is calling it (the browser, your ajax call, etc).
You also probably want to have header('Content-Type: application/json'); in your PHP file to make things all right and proper.
No, there is no problem with your ajax setup, it's because the return is used with PHP objects or variables and it can't return a value to other language like javascript. when you are using echo it sends the values to HTTP response so your ajax response can handle it.
The best way to do complex data is to send them in arrays like:
$arr = array();
$arr['res'] = 'something';
$arr['res2'] = 'somethingelse';
echo json_encode($arr);
and then you can handle it as object.parameter in your jquery code as I have specified it before in this example.
Always make echo or print or parsing php as html file in ajax call and then get the data, this will save you a lot of efforts.
the ajax is just reading the file, there is no way to make calls in two different languages PHP and JS.
The JS just returned the filed from the server, if it was php then it will interpreted and go to the Ajax call as html or else possible.

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

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

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

Categories