Missing template while using Ajax-Plugin from dereuromark

Hello there,

I’m trying to use the Ajax plugin (dereuromark/cakephp-ajax). I’ve CakePHP 4.4.12 running and set up the plugin as mentioned in readme. When I make my Ajax call, I receive a json-formatted response which contains the keys “error”, “success” and “content”. The value of “error” is a html error page telling me, the template [controllername]/ajax/index.php is missing. But as I’m using the AjaxComponent such a template should not be necessary.

I would expect, that a json-response would automatically be created and returned if it is an Ajax request, otherwise, the “normal” view would be rendered.

Can sb. help me / give me advice?

Actual response:

{
    "error": {
        "xdebug_message": "<tr><th align='left' bgcolor='#f57900' colspan=\"5\"><span style='background-color: #cc0000; color: #fce94f; font-size: x-large;'>( ! )</span> Cake\\View\\Exception\\MissingTemplateException: Template file `Articles/ajax/index.php` could not be found.\n\nThe following paths were searched:\n............"
    }
    "content": null
    "success": false

routes.php

$routes->scope('/', function (RouteBuilder $routes) {

   Router::extensions(['json']);
   ...
}

Application.php

public function bootstrap(): void
{
        // Call parent to load bootstrap from files.
        parent::bootstrap();
        $this->addPlugin('Ajax', ['bootstrap' => true]);

AppController.php

public function initialize(): void
{
    parent::initialize();
    $this->loadComponent('Ajax.Ajax');
}

public function beforeRender(\Cake\Event\EventInterface $event)
{
    parent::beforeRender($event);

    if ($this->request->is('ajax')) {
          $this->viewBuilder()->setClassName('Ajax.Ajax');
    }
}

A Controller

public function viewClasses(): array {
        if (!$this->request->getParam('_ext')) {
            return [];
        }

        return [JsonView::class];
    }

public function index()
    {
        $this->request->allowMethod(['ajax', 'get']);

       
        $data = $this->paginate($this->Articles);

        //From sandbox "simple.php" (dereuromark)
        if ($this->request->is(['ajax'])) {
            // Lets create current datetime
            $now = date("d-m-Y-H-i-s");
            $this->set('result', ['now' => $now]);
            $this->set('_serialize', ['result']);
        }
        else
        {
             $this->set(compact('data'));
             $this->set('_serialize', ['data']);
        }
    }

view

function ajaxTest()
{
    $.ajax({
        url: '/articles/index.json',
        method: 'get',
        dataType: 'json',
        success: function(data) {
            alert(data);
        },
        error: function(xhr, status, error) {
            alert(error);
        }
    });
}

Thanks in advance.

Hello, I made some progress. After stepping through AjaxView.php (from Plugin) I saw, that rendering will be skipped, when the var “success” is set. I tried by modifying my code like this:

        if ($this->request->is(['ajax'])) {
            // Lets create current datetime
            $now = date("d-m-Y-H-i-s");
            $this->set('result', ['now' => $now]);
            $this->set('success', true);
            $this->set('_serialize', ['success', 'result']);
        }

Now, the response seems ok, but why I have to set “success” and how to handle errors? I thought, the AjaxComponent of cakephp-ajax handles this for us. Did I get sth. wrong or has this behavior changed? Looking at the sandbox code (cakephp-sandbox/plugins/Sandbox/src/Controller/AjaxExamplesController.php at 32b30a842bd1d6af078c928c1433c1d3be3b9d03 · dereuromark/cakephp-sandbox · GitHub), there is no need for a success variable.

{
    "error": null,
    "success": true,
    "content": null,
    "_message": null,
    "result": {
        "now": "07-07-2024-07-34-35"
    }
}

try to return it as json type, are you tring to get data or submit data?

Thanks. I’m trying to “GET” data. I noticed, that when I render an element, it also works correctly. It’s just for the case, when I want to return “plain” data.

So this also works:

if ($this->request->is('ajax')) {
    $this->render('/element/Articles/test');
}

Output is json

_message: null
content: "<div class=\"row\">↵  ... <table>↵           …"
error: null
success: null

Then, just like you suggested, I tried to set the return type as json and also ajax but get the same error.

$this->response = $this->response->withType('json');
//or also
$this->response = $this->response->withType('ajax');

But despite of this specific return problem, the whole plugin works as expected and documented. Tested it with the “delete” action and corresponding documentation.

$result = [‘test’ => ‘data’];
return $this->response->withType(‘application/json’)
->withStringbody(json_encode($result));

you can try this in your controller

In Cake 3.1, when you don’t want to use view/template file you can set
$this->autoRender = false
or maybe in your case when you have action named “index” but view named “ajaxTest” try to use $this->render('ajaxTest');

If you directly return JSON data and don’t need templating, then don’t use the AJAX plugin
The whole idea of the ajax plugin, as the sandbox and the plugin itself explains is to render templated elements more easily. For both normal and AJAX use case without having to create different ones.
So in your case you should be able to directly use JSON view instead, that’s it, nothing else needed.

2 Likes

Hello guys,

thanks for the explanation. I just was afraid of setting it up wrong. I read about the use cases for that plugin but I forgot it while playing with it.

Many thanks for your help.

1 Like