Return raw HTML results from Magento 2 controllers

Likes (1)   Dislikes (0)  
  (1 reviews)

Sometimes in Magento 2 development, we come across situations where we need to return a compiled PHTML file in an ajax request. And we don’t want the full layout as well, just the content from the PHTML template. That is we want to return raw HTML from Magento 2 controller without having the surrounding layout which can later be dumped on any PHTML.

The problem statement

We can not use Page Layout type as it will render with the surrounding layout. Which will generate nested HTML in the dom tree. And with an ajax request, we don’t want the layout to be dumped again in the template.

For ajax controllers, those return JSON results are okay to deal with because we can anyhow manage to deal with that. We can either use the JSON result to do some calculations or compose HTML out of it using JavaScript. But what if composing the HTML in JavaScript is difficult we have to build quite a long and complex HTML structure. What if we already have a PHTML template for it and we want to reuse it in the ajax controller?

The Solution

Instead of using a page layout for the controller, we can totally neglect the layout file for the controller. If the existing controller is really required but still we need to somehow make an ajax request to the same controller and need to get only template content as output, we have to create another controller for that purpose. The ajax controller doesn’t need a layout handler as we don’t need full output with the layout. Instead, we will build the layout inside the controller’s execution method.

PHP
$layoutFactory = $this->_objectManager->get(LayoutFactory::class);

Then we can attach the desired block class on the top of the layout and call the public method toHtml() on it. We may set the template as well if the block class does not define one and can also add a view model instance if required by the template.

PHP
$output = $layoutFactory->create()
            ->createBlock(\Magento\Framework\View\Element\Template::class)
            ->setViewModel($viewModel)
            ->setTemplate('<Namespace_ModuleName>::<template file path>.phtml')
            ->toHtml();

This will compile our template file using the given block class and the view model and finally return the HTML. Next, we have to initialize the raw result instance of Magento 2 Controller results and feed the generated HTML to it.

PHP
/** @var Raw $rawResult */
$rawResult = $this->resultFactory->create(ResultFactory::TYPE_RAW);
return $rawResult->setContents($output);

Sample Ajax Controller

PHP
<?php

declare(strict_types=1);

namespace Training\CookieConsent\Controller\Index;

use Magento\Framework\Controller\Result\Raw;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\View\LayoutFactory;

/**
 * Frontend interface for customers to manage cookie acceptance
 */
class Index extends \Magento\Framework\App\Action\Action
{
    public function execute()
    {

        $viewModel = $this->_objectManager->get(\Training\CookieConsent\ViewModel\ManageCookies::class);

        $layoutFactory = $this->_objectManager->get(LayoutFactory::class);
        $output = $layoutFactory->create()
            ->createBlock(\Magento\Framework\View\Element\Template::class)
            ->setViewModel($viewModel)
            ->setTemplate('Training_CookieConsent::manage-cookies.phtml')
            ->toHtml();

        /** @var Raw $rawResult */
        $rawResult = $this->resultFactory->create(ResultFactory::TYPE_RAW);
        return $rawResult->setContents($output);
    }
}

Using the Ajax Controller In Your Template

You can call the above controller using asynchronous ajax call and after getting the raw html content dump into the modal content area for example. For the CSS for the dumped content I would suggest a unique and separate css file of its own which you need to include at the top level (the page html).

PHP
<script>
  require([
    'jquery'
  ], function($) {
    $(document).ready(function() {
      $('#toggle-popup').click(function() {
        $.ajax({
          method: 'GET', // POST depending on your requirement
          url: '<?= $block->getUrl('training/cookieconsent/index') ?>',
          showLoader: true
        }).then(function(res) {
          $('#my-modal.modal-content').html(res).trigger('contentUpdated'); // the raw html got dumped in the target container 
        });
      });
    });
  });
</script>

Conclusion

This helps in reusing existing templates with ajax controller. You can use this approach to load any of your template in asynchronous way.

See How to Implement Magento 2 ViewModel in Your PHTML Template Files.

Let us know below in the comment how you are developing your ajax controller that must use a block template file and return html as output. Or any other issues if you have with your ajax request.

1 thought on “Return raw HTML results from Magento 2 controllers”

Leave a Comment

Share via
Copy link
Powered by Social Snap