-1

I am setting few view variables within my App controller such as company name, address, contact information which changes based on sub domains so that they are available throughout all view templates. However I am struggling to identify why the are not available when making ajax request.

//App Controller beforeFilter

$this->set('company', 'Test Company');
$this->set('address', '14 Test Street, Test, TE5 3ST');
$this->set('email', 'test@test.com');

Above variable are available for all none ajax i.e when I am not rendering specific template request however for below example request I am not able to access those variables in test_data template.

function _ajaxGetTestData() 
{
    $view = new View();
    $content = $view->render('Home/Ajax/test_data');
    $response['content'] = $content;
    $response['success'] = TRUE;

    $this->set(compact('response'));
    $this->set('_serialize', ['response']);
}
user4676307
  • 409
  • 8
  • 22

3 Answers3

0

That is because you did not serialize the variables from the app controller.

You can try in your method:

$response['company'] = $company;
$response['address'] = $address;
$response['email'] = $email;

Or https://book.cakephp.org/3/en/views/json-and-xml-views.html#using-a-data-view-with-template-files

Salines
  • 5,674
  • 3
  • 25
  • 50
0

You have to set view variables before render is called.

$this->set('data');
$this->render('custom_view');
Shifat
  • 732
  • 1
  • 6
  • 20
0

When you call $this->set it sets the view variables on the Controller class. These variables are eventually passed to the View Builder, which creates a new View class and returns a Result containing the HTML for this new View.

When you want to render your own View manually you need to pass it the view variables manually too - $this->set isn't setting view variables in this new View class you created here:

$view = new View();
$content = $view->render('Home/Ajax/test_data'); // Has nothing to do with $this->set, you'd have to pass the variables in manually

This isn't generally the simplest approach to take to render an AJAX view. While you can generally continue to use $this->set in beforeFilter as you already are:

public function beforeFilter(Event $event)
{
    $this->set('company', 'Test Company');
    $this->set('address', '14 Test Street, Test, TE5 3ST');
    $this->set('email', 'test@test.com');    
}

.. the easiest method to make an AJAX-compatible is to enable the JSON/XML handler let the built-in JSON/XML renderers do their magic.

In the action function (index/view/edit/whatever) just include the company/address/email in the _serialize variable.

For example, a "view" function might look like:

public function view($id = null)
{
   // Do regular view stuff:
   $entity = $this->MyTable->get($id);
   $this->set('entity', $entity);

   // Include ALL the variables you want in the response in _serialize:
   $this->set('_serialize', ['entity', 'company','address', 'email']);
}

If you are sure you need a custom template (which isn't required), don't render it manually, just set the template when AJAX is detected:

if($this->request->is('ajax')){
    $this->viewBuilder()->setTemplate('Home/Ajax/test_data');
}

This will automatically be rendered for you, using the variables you set with $this->set.

If you want to make a global custom template (for example, wrapping all your data with a "response" node), for all AJAX requests, use a new Layout instead of a custom template:

if($this->request->is('ajax')){
    $this->viewBuilder()->setLayout('custom_json');
}

Create this layout in src/Template/Layout/custom_json.ctp and format it as you wish, for example:

<?php
/**
 * @var \App\View\AppView $this
 */
?>
{"response": <?= $this->fetch('content') ?> }

See from docs:

Andy Hoffner
  • 3,267
  • 2
  • 21
  • 22