We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Get rendered view contents and transform it into a json-object on ajax requests with the use of events

I have a project where I want to return two different outputs based on if it is AJAX or not.

When I query GET /controller/action I want it to display a view (x) that extends view (y) as HTML. When I query the same action with AJAX, I want it to display only the contents og view x in a JSON-object.

Example: view x:

{% extends "y.volt" %}
{% block footer %}
<h1>Test</h1>
{% endblock %}

If it is an AJAX request, I want to output the following:

echo json_encode(array('some' => 'data', 'contents' => '<h1>Test</h1>'));

I have started out with the following in my Base Controller:

public function afterExecuteRoute(\Phalcon\Mvc\Dispatcher $dispatcher) {
    if ($this->request->isAjax()) {
        $this->config->is_ajax = true;
        $this->view->setRenderLevel(\Phalcon\Mvc\View::LEVEL_ACTION_VIEW);
    }
}

But what event do I have to make to catch the rendered view, and transform it into a json-object? This is what I want, but what events and which functions do I have to use?

public function afterRenderedView() {
    if($this->config->is_ajax) {
        $this->response->setContentType('application/json', 'UTF-8');
        $this->response->setContent(json_encode(array('some' => 'data', 'contents' => $this->view->getContents())));
        return false;
    }
}


2.1k
Accepted
answer

I guess you would need eventManager to achieve that.

In your afterExecuteRoute, you could attach your json processing :

public function afterExecuteRoute(\Phalcon\Mvc\Dispatcher $dispatcher) {
    if ($this->request->isAjax()) {
        $this->config->is_ajax = true;
        $this->view->setRenderLevel(\Phalcon\Mvc\View::LEVEL_ACTION_VIEW);
        $this->response->setContentType('application/json', 'UTF-8');

        /* hook to afterRender event */
        if (null == $this->view->getEventsManager()){
            $eventManager = new \Phalcon\Events\Manager();
            $this->view->setEventsManager($eventManager);
        }
        else {
            $eventManager = $this->view->getEventsManager();
        }
        $eventManager->attach("view:afterRender", new Jsonview());
    }
}

while Jsonview class could be as simple as:

class Jsonview {
    public function afterRender($event, $view){
        /* replace content as json */
        $result = array("contents" => $view->getContent());
        $view->setContent(json_encode($result));
    }
} 

Perfect, that worked! Thanks!



12.2k

Hi. I've created dispatcher for this. Inspired by Laravel5 this thread and this one The best way for JSON response.

$di->set(
    'dispatcher',
    function () use ($di) {
        $eventsManager = $di->getShared('eventsManager');
        /**
         * Handle exceptions and not-found exceptions using NotFoundPlugin
         */

        $eventsManager->attach('dispatch:afterExecuteRoute', function($event, $dispatcher, $exception) use ($di){
            if ($di->get('request')->isAjax()) {

                $di->get('view')->disableLevel(array(
                    View::LEVEL_ACTION_VIEW => true,
                    View::LEVEL_LAYOUT => true,
                    View::LEVEL_MAIN_LAYOUT => true,
                    View::LEVEL_AFTER_TEMPLATE => true,
                    View::LEVEL_BEFORE_TEMPLATE => true
                ));
                $di->get('response')->setContentType('application/json', 'UTF-8');

                /* hook to afterRender event */
                if (null == $di->get('view')->getEventsManager()){
                    $eventManager = new \Phalcon\Events\Manager();
                    $di->get('view')->setEventsManager($eventManager);
                }
                else {
                    $eventManager = $di->get('view')->getEventsManager();
                }
                $eventManager->attach("view:afterRender", function ($event, $view) use ($di){
                    $result = array("contents" => $view->getParamsToView());
                    $view->setContent(json_encode($result));
                });
            }
        });

        $dispatcher = new Phalcon\Mvc\Dispatcher();

        $dispatcher->setEventsManager($eventsManager);
        return $dispatcher;
    },
    true
);

Now in controller all variables which were passed to view become a JSON string

<?php

class IndexController extends ControllerBase
{

    public function indexAction()
    {
        $this->view->page = 1;
        $this->view->pages = [1,2,3,4,5];
        $this->view->setVars(array('products' => [1,2,3,4,5]));
        //{"contents":{"page":1,"pages":[1,2,3,4,5],"products":[1,2,3,4,5]}}
    }

}

Thanks

edited Oct '15

.js Ajax request:

$.ajax({ type: $('#myform').attr('method'), url: $('#myform').attr('action'), data: $('#myform').serialize(), dataType: "JSON", success: function (data) { alert(data); } });

Controller:

$result = $myModel->getReadConnection()->query($sql)->fetchAll(); // Or fecthAll()

            $response = new \Phalcon\Http\Response();
            //Set the content of the response
            $response->setContentType('application/json', 'UTF-8');
            $response->setContent(json_encode($result));
            //Return the response
            return $response;

//getting result on console

[{0: "248", 1: "Sameer", 2: "[email protected]", 3: "", 4: "", 5: "", 6: "", 7: "", 8: "", 9: "",…}]

How can i decode this response on my view (list.volt).

Thanks a lot.

edited Oct '15

Hi,

I got it... DataTable can be used for it .js Ajax

                        $('#form_id').submit(function(ev){
                            var oTable = $('#subslist').dataTable();
                            $.ajax({
                                type: $('#form_id').attr('method'),
                                url: $('#form_id').attr('action'),
                                data: $('#form_id').serialize(),
                                dataType: 'json',
                                success: function(s){
                                    oTable.fnClearTable();
                                    for(var i = 0; i < s.length; i++) {
                                        oTable.fnAddData([
                                            s[i]['name'],
                                            s[i]['email'],
                                            s[i]['designation'],
                                            s[i]['category'],
                                            s[i]['companyname']
                                        ]);
                                    } // End For
                                },
                                error: function(e){
                                    $('body').loadingOverlay('remove');
                                }
                            });
                            ev.preventDefault();
                        });

In volt. <form id="form_id" method="POST" action="yourAction"> <your elements> </form>

            <table id="subslist" class="display" cellspacing="0" width="100%">
                <thead>
                <tr>
                    <th>Name</th>
                    <th>Email</th>
                    <th>Designation</th>
                    <th>Category</th>
                    <th>Company</th>
                </tr>
                </thead>
            </table>

Thanks