How to use AJAX in CakePHP 3.5?


#1

I’m following the example below, but I can not make it work

Example: http://sandbox.dereuromark.de/sandbox/ajax-examples/simple

The function is called correctly but I do not retrieve the required value. These are my files …

test/src/Template/Layout/default.ctp

// add this line
<?= $this->Html->script('jquery.min.js') ?>

test/src/Controller/AjaxController.php

<?php
namespace App\Controller;

use App\Controller\AppController;
use Cake\I18n\Date;
use Cake\I18n\Time;

class AjaxController extends AppController 
{
    public function index() 
    {
    }

    public function simple() 
    {
    }

    public function simpleAction() 
    {
        $this->log('You are here', 'debug');
        if ($this->request->is(array('ajax'))) 
        {
            // lets create current datetime
            $now = new Time();
            $date = new Date();
            $this->set('result', array('now' => $now));
            $this->set('_serialize', array('result'));
        }
    }
}

test/src/Template/Ajax/simple.ctp

<script type="text/javascript">
$(function() 
{
    $('#button').click(function() 
    {
        var targeturl = $(this).attr('rel');
        $.ajax({
            type: 'get',
            url: targeturl,
            beforeSend: function(xhr) 
            {
                xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
            },
            success: function(response) 
            {
                if (response.result) 
                {
                    var result = response.result;
                    $('#result').html(result.now);
                }
            },
            error: function(e) 
            {
                alert("An error occurred: " + e.responseText.message);
                console.log(e);
            }
        });
    });
});
</script>

<div class="index large-9 medium-8 columns content">
    <h2>Simple JSON Response</h2>

    <p>
    In this simple example we request something via JSON GET request.
    The response will be an object and its content is accessable via `response.result`. The result itself can contain multiple data keys.
    We just need our `result.now` date value.
    </p>

    <?php 
    $request = $this->Url->build(['controller' => 'ajax', 'action' => 'simpleAction', 'ext' => 'json']);
    ?>
    <button id="button" rel="<?= $request ?>">Click me</button>

    <h3>Resultado</h3>
    <div id="result">
        <i>n/a</i>
    </div>

</div>

logs/error.log

2017-10-19 14:39:45 Error: [LogicException] Controller actions can only return Cake\Http\Response or null.
Request URL: /ajax/simple-action?ext=json
Referer URL: http://localhost/test/ajax/simple
Stack Trace:
#0 /var/www/html/test/vendor/cakephp/cakephp/src/Http/ActionDispatcher.php(93): Cake\Http\ActionDispatcher->_invoke($
#1 /var/www/html/test/vendor/cakephp/cakephp/src/Http/BaseApplication.php(103): Cake\Http\ActionDispatcher->dispatch$
#2 /var/www/html/test/vendor/cakephp/cakephp/src/Http/Runner.php(65): Cake\Http\BaseApplication->__invoke(Object(Cak$
#3 /var/www/html/test/vendor/cakephp/cakephp/src/Routing/Middleware/RoutingMiddleware.php(107): Cake\Http\Runner->__$
#4 /var/www/html/test/vendor/cakephp/cakephp/src/Http/Runner.php(65): Cake\Routing\Middleware\RoutingMiddleware->__i$
#5 /var/www/html/test/vendor/cakephp/cakephp/src/Routing/Middleware/AssetMiddleware.php(88): Cake\Http\Runner->__inv$
#6 /var/www/html/test/vendor/cakephp/cakephp/src/Http/Runner.php(65): Cake\Routing\Middleware\AssetMiddleware->__inv$
#7 /var/www/html/test/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php(93): Cake\Http\Runner->$
#8 /var/www/html/test/vendor/cakephp/cakephp/src/Http/Runner.php(65): Cake\Error\Middleware\ErrorHandlerMiddleware->$
#9 /var/www/html/test/vendor/cakephp/debug_kit/src/Middleware/DebugKitMiddleware.php(52): Cake\Http\Runner->__invoke$
#10 /var/www/html/test/vendor/cakephp/cakephp/src/Http/Runner.php(65): DebugKit\Middleware\DebugKitMiddleware->__inv$
#11 /var/www/html/test/vendor/cakephp/cakephp/src/Http/Runner.php(51): Cake\Http\Runner->__invoke(Object(Cake\Http\S$
#12 /var/www/html/test/vendor/cakephp/cakephp/src/Http/Server.php(81): Cake\Http\Runner->run(Object(Cake\Http\Middle$
#13 /var/www/html/test/webroot/index.php(40): Cake\Http\Server->run()
#14 {main}

#2

Things to check:

Is your call able to reach the function? Are you getting “You are here” logged to debug.log?

Your function is clearly not returning any response as indicated by the error message. Have you loaded the RequestHandler component?
$this->loadComponent('RequestHandler');

And lastly, you need to return the results as json response type. Try adding the following before your $this->set()

    $resultJ = json_encode(array('result' => array('now' => $now)));
    $this->response->type('json');
    $this->response->body($resultJ);
    return $this->response;

#3

Thank sourjya

Had tried with “return json_encode($ now);” but also caused error.

In the end it was like that and it works correctly.

test/src/Controller/AjaxController.php

public function simpleAction() 
{
    if ($this->request->is(array('ajax'))) 
    {
        $now = new Time();

        // the order of these three lines is very important !!!
        $resultJ = json_encode(array('result' => array('now' => $now)));
        $this->response->type('json');
        $this->response->body($resultJ);

        return $this->response;
    }        
}

#4

Just a suggestion, use the new Cake\Http\Response functions format withType() withBody() etc:
https://book.cakephp.org/3.0/en/controllers/request-response.html#setting-the-body

$json_data = json_encode($data);
$response = $this->response->withType('json')->withStringBody($json_data);
return $response;

#5

in AppController.php add a method

    public function json($data){
        $this->response->type('json');
        $this->response->body(json_encode($data));
        return $this->response;
    }

and in your ***Controller.php or any other controller

public function simpleAction() {
  if (this->request->is('ajax') && this->request->is('post') ){
    $res = [
        'data' => [
             /* your data */
         ]
    ];
   return $this->json($res);
  }
}