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

StackOverflow https://stackoverflow.com/questions/23322172

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

有帮助吗?

解决方案

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?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top