Magento Ajax - how to programmatically display custom block from Controller (my HTML content is always blank)

18,524

I find these things very difficult. I am going to try to answer in two parts:

PART ONE

You may want to try to render the layout in the controller so try this first then read the additional items below:

//file: app/code/local/MyModule/Ajax/controllers/ProductController.php
//class: MyModule_Ajax_ProductController
//function: indexAction()
$this->loadLayout();
$this->renderLayout();

BUT you are making an Ajax module. So you might want to utilise controller methods such as:

//set the response
$this->getResponse()
//->clearHeaders()
->setHeader('Content-Type', 'application/json')
->setBody(json_encode($someReturnObject));
    return;

And if you want to setBody() to a block's HTML then in the controller the code you have posted above is looking good (but see part two below):-

  $this->loadLayout();
  $myBlock = $this->getLayout()->createBlock('ajax/product');
  $myBlock->setTemplate('mymodule_ajax/product.phtml');
  $myHtml =  $myBlock->toHtml(); //also consider $myBlock->renderView();     
  $this->getResponse()
       ->setHeader('Content-Type', 'text/html')
       ->setBody($myHtml);
  return;

And actually even just calling exit(); at the end of indexAction() will flush the PHP output buffer to the browser.

I note that you are making a product controller. Studying the code in the class you are extending may help:

//file: app/code/core/Mage/Catalog/controllers/ProductController.php
//class: Mage_Catalog_ProductController
//function: viewAction()
    public function viewAction()
    {
        // Get initial data from request
        $categoryId = (int) $this->getRequest()->getParam('category', false);
        $productId  = (int) $this->getRequest()->getParam('id');
        $specifyOptions = $this->getRequest()->getParam('options');

        // Prepare helper and params
        $viewHelper = Mage::helper('catalog/product_view');

        $params = new Varien_Object();
        $params->setCategoryId($categoryId);
        $params->setSpecifyOptions($specifyOptions);

        // Render page
        try {
            $viewHelper->prepareAndRender($productId, $this, $params);
        } catch (Exception $e) {
            //...
        }
    }

which might give you some ideas about sending Magento-standard product-related HTML to the browser. You may find the prepareAndRender() helper function more interesting but ultimately it uses $this->renderLayout() to create the output html (here $this is the controller).


PART TWO

I think you need to concentrate on the line in your code:

    echo $this->getLayout()->createBlock('ajax/product')->setTemplate('mymodule_ajax/product.phtml')->toHtml();

and either change it to

    echo $this->getLayout()->createBlock('mymodule_ajax/product')->setTemplate('mymodule_ajax/product.phtml')->toHtml();

or, in your module's config.xml file add something like: (I think this is the answer you need)

<config>
  <global>
        <!-- ... -->

        <blocks>
            <ajax>
                <class>MyModule_Ajax_Block</class>
            </ajax>
        </blocks>

        <!-- ... -->
  </global>
</config>

so that Magento can understand that createBlock('ajax/product') means MyModule_Ajax_Block_Product and not Mage_Ajax_Block_Product.

I also recommend you change MyModule to Mymodule throughout so that there is not a capital letter in the middle. Because

$this->getLayout()->createBlock('mymodule_ajax/product')

well, I don't understand the fine details but generally Magento will make mymodule into Mymodule not MyModule

Does that make sense?

Share:
18,524
Natacha Beaugeais
Author by

Natacha Beaugeais

Updated on June 04, 2022

Comments

  • Natacha Beaugeais
    Natacha Beaugeais almost 2 years

    I am trying to display a block as part of a response to an ajax call. Everything is working except I cannot get the controller to echo the template HTML code.

    My module class:

    class MyModule_Ajax_ProductController extends Mage_Catalog_ProductController {
    
        public function indexAction() {
    
            if ($product = $this->_initProduct()) {
    
                echo '<div>hello</div>'; //this works
    
                echo $this->getLayout()->createBlock('ajax/product')->setTemplate('mymodule_ajax/product.phtml')->toHtml();
    
                //I also tried:
                //$layout = $this->getLayout();
                //$update = $layout->getUpdate();
                //$update->load('ajax_product_index'); 
                //$layout->generateXml();
                //$layout->generateBlocks();
                //$output = $layout->getOutput();
                //echo $output;
    
            }
        }
    }
    

    Inside my template file product.phtml - this HTML never gets shown. (saved to app/design/frontend/default/default/template/mymodule_ajax/product.phtml)

    <div>HERE!</div>
    

    My block class:

    class MyModule_Ajax_Block_Product extends Mage_Catalog_Block_Product
    {
        private $product;
    
        protected function _construct()
        {
            parent::_construct();
            $this->setTemplate('mymodule_ajax/product.phtml');
        }
    
        protected function _toHtml() {
            return parent::_toHtml();
        }
    
        public function setProduct($product) {
            $this->product = $product;
            return $this;
        }
    
        public function getProduct() {
            return $this->product;
        }
    
    }
    

    My layout/mymodule_ajax.xml

    <?xml version="1.0"?>
    <layout>
    
        <ajax_product_index>
            <reference name="root">
                <block type="ajax/project" name="root" output="toHtml" template="mymodule_ajax/product.phtml"/>
            </reference>
        </ajax_product_index>
    
    </layout>
    

    I am assuming that because I am setting up the template programmatically in my block class I shouldn't need the module reference? Removing the reference makes no difference.

    I get no PHP errors, the HTML displayed renders

    <html>
    <head></head>
    <body></body>
    </html>
    

    I simply can't figure out what I am doing wrong? I'm using Magento CE 1.8.1

  • Natacha Beaugeais
    Natacha Beaugeais almost 10 years
    This all makes sense, yes - thank you so much for all the detail. I am going to go through this now with a fine toothed comb. Hopefully one of your answers help me and saves my sanity... I will get back to you on this soon.
  • Natacha Beaugeais
    Natacha Beaugeais almost 10 years
    THANK YOU. Your detailed answer, explanations etc led me down the path to a resolution. In the end, it was the naming of my block in the code, and the incorrect naming of my template file and folder structure - The system couldn't finding my template but instead of telling me so, it was returning an empty string. This one was super hard to track and debug!!