I am having a ajax post call to a cakePhp Controller:
$.ajax({
type: "POST",
url: 'locations/add',
data: {
abbreviation: $(jqInputs[0]).val(),
description: $(jqInputs[1]).val()
},
success: function (response) {
if(response.status === "success") {
// do something with response.message or whatever other data on success
console.log('success');
} else if(response.status === "error") {
// do something with response.message or whatever other data on error
console.log('error');
}
}
});
When I try this I get the following error message:
Controller actions can only return Cake\Network\Response or null.
Within the AppController I have this
$this->loadComponent('RequestHandler');
enabled.
the Controller function looks like this:
public function add()
{
$this->autoRender = false; // avoid to render view
$location = $this->Locations->newEntity();
if ($this->request->is('post')) {
$location = $this->Locations->patchEntity($location, $this->request->data);
if ($this->Locations->save($location)) {
//$this->Flash->success(__('The location has been saved.'));
//return $this->redirect(['action' => 'index']);
return json_encode(array('result' => 'success'));
} else {
//$this->Flash->error(__('The location could not be saved. Please, try again.'));
return json_encode(array('result' => 'error'));
}
}
$this->set(compact('location'));
$this->set('_serialize', ['location']);
}
What do I miss here? Is there any additional settings needed?
To return JSON from the server, you must include the JSON data in the body of the HTTP response message and provide a "Content-Type: application/json" response header. The Content-Type response header allows the client to interpret the data in the response body correctly.
On document ready state send an AJAX GET request to 'ajaxfile. php' . Loop through all response values and append a new row to <table id='userTable'> on AJAX successfully callback. Note – For handling JSON response you have to set dataType: 'JSON' while sending AJAX request.
If you want to return JSON, you need to have the JSON string as the only text returned. This is not possible using client side JavaScript for the reason you've seen. You should amend your JSON feed to be a server-side resource.
The JSON return tag delivers data directly to a first-party page in JSON format. Real-time parsing or targeting can pull data out of the DOM at the time the page is rendered.
Instead of returning the json_encode result, set the response body with that result and return it back.
public function add()
{
$this->autoRender = false; // avoid to render view
$location = $this->Locations->newEntity();
if ($this->request->is('post')) {
$location = $this->Locations->patchEntity($location, $this->request->data);
if ($this->Locations->save($location)) {
//$this->Flash->success(__('The location has been saved.'));
//return $this->redirect(['action' => 'index']);
$resultJ = json_encode(array('result' => 'success'));
$this->response->type('json');
$this->response->body($resultJ);
return $this->response;
} else {
//$this->Flash->error(__('The location could not be saved. Please, try again.'));
$resultJ = json_encode(array('result' => 'error', 'errors' => $location->errors()));
$this->response->type('json');
$this->response->body($resultJ);
return $this->response;
}
}
$this->set(compact('location'));
$this->set('_serialize', ['location']);
}
Since CakePHP 3.4, we should use
return $this->response->withType("application/json")->withStringBody(json_encode($result));
Instead of :
$this->response->type('json');
$this->response->body($resultJ);
return $this->response;
CakePHP Documentation
Most answers I've seen here are either outdated, overloaded with unnecessary information, or rely on withBody()
, which feels workaround-ish and not a CakePHP way.
Here's what worked for me instead:
$my_results = ['foo'=>'bar'];
$this->set([
'my_response' => $my_results,
'_serialize' => 'my_response',
]);
$this->RequestHandler->renderAs($this, 'json');
More info on RequestHandler
. Seemingly it's not getting deprecated anytime soon.
UPDATE: CakePHP 4
$this->set(['my_response' => $my_results]);
$this->viewBuilder()->setOption('serialize', true);
$this->RequestHandler->renderAs($this, 'json');
More info
there are few things to return JSON
response:
RequestHandler
componentjson
_serialize
valuefor example you can move first 3 steps to some method in parent controller class:
protected function setJsonResponse(){
$this->loadComponent('RequestHandler');
$this->RequestHandler->renderAs($this, 'json');
$this->response->type('application/json');
}
later in your controller you should call that method, and set required data;
if ($this->request->is('post')) {
$location = $this->Locations->patchEntity($location, $this->request->data);
$success = $this->Locations->save($location);
$result = [ 'result' => $success ? 'success' : 'error' ];
$this->setJsonResponse();
$this->set(['result' => $result, '_serialize' => 'result']);
}
also it looks like you should also check for request->is('ajax)
; I'm not sure about returning json
in case of GET
request, so setJsonResponse
method is called within if-post
block;
in your ajax-call success handler you should check result
field value:
success: function (response) {
if(response.result == "success") {
console.log('success');
}
else if(response.result === "error") {
console.log('error');
}
}
In the latest version of CakePHP $this->response->type()
and $this->response->body()
are deprecated.
Instead you should use $this->response->withType()
and $this->response->withStringBody()
E.g:
(this was pinched from the accepted answer)
if ($this->request->is('post')) {
$location = $this->Locations->patchEntity($location, $this->request->data);
if ($this->Locations->save($location)) {
//$this->Flash->success(__('The location has been saved.'));
//return $this->redirect(['action' => 'index']);
$resultJ = json_encode(array('result' => 'success'));
$this->response = $this->response
->withType('application/json') // Here
->withStringBody($resultJ) // and here
return $this->response;
}
}
Relevant Documentation
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With