Magento 2でAJAXを使用してHTMLをレンダリングする方法


12

Magento 2でAJAXを介してHTMLをレンダリングする最良の方法を見つけようとしています。

方法1:レイアウトなしでコントローラーを使用する

ファイル Foo/Bar/Controller/Popin/Content.php

<?php

namespace Foo\Bar\Controller\Popin;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;

/**
 * Class Content
 */
class Content extends Action
{

    /**
     * Content constructor.
     *
     * @param Context $context
     */
    public function __construct(
        Context $context
    ) {
        parent::__construct($context);
    }

    /**
     *
     */
    public function execute()
    {
        /** @var \Magento\Framework\View\Layout $layout */
        $layout = $this->_view->getLayout();

        /** @var \Foo\Bar\Block\Popin\Content $block */
        $block = $layout->createBlock(\Foo\Bar\Block\Popin\Content::class);
        $block->setTemplate('Foo_Bar::popin/content.phtml');

        $this->getResponse()->setBody($block->toHtml());
    }
}   

方法2:カスタムレイアウトでコントローラーを使用する

ファイル Foo/Bar/Controller/Popin/Content.php

<?php

namespace Foo\Bar\Controller\Popin;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;

/**
 * Class Content
 */
class Content extends Action
{

    /**
     * Content constructor.
     *
     * @param Context $context
     */
    public function __construct(
        Context $context
    ) {
        parent::__construct($context);
    }

    /**
     *
     */
    public function execute()
    {
        $this->_view->loadLayout();
        $this->_view->renderLayout();
    }
}    

ファイル Foo/Bar/view/frontend/page_layout/ajax-empty.xml

<?xml version="1.0"?>

<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_layout.xsd">
    <container name="root"/>
</layout>

ファイル Foo/Bar/view/frontend/layout/foo_bar_popin_content.xml

<?xml version="1.0"?>

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="ajax-empty" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="root">
            <block class="Foo\Bar\Block\Popin\Content" name="foo_bar_popin_content" template="Foo_Bar::popin/content.phtml" cacheable="false"/>
        </referenceContainer>
    </body>
</page>

IMOのベストプラクティスは、ロジックをコントローラーから分離するため、方法2のようです。
しかし、問題とウェイ2は、ということである<body><head>してCSS/ JSそれはそれで唯一の私のブロックテンプレートを完全にクリーンなHTMLではないので、生成されます。

  • カスタムレイアウトを間違って使用していますか?
  • されるウェイ1は良い習慣であると考えていますか?
  • それを行う他の方法はありますか?

回答:


18

私も2の方法を使用します。実際、実際には、AJAXを介して「純粋な」HTMLを、ヘッド、ボディ、CSSなどなしでレンダリングできます。

秘訣は:

  • タイプ\Magento\Framework\View\Result\Layoutではなくタイプの応答をインスタンス化するようにコントローラに指示する\Magento\Framework\View\Result\Page
  • <layout...>...</layout>ではなく、ルートノードでレイアウトXMLファイルを使用する<page...>...</page>

これは非常に単純な実装です。

コントローラー

<?php    
namespace Namespace\Module\Controller\Index;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\ResultFactory;

class Index extends Action
{
    /**
     * Dispatch request
     *
     * @return \Magento\Framework\Controller\ResultInterface|ResponseInterface
     * @throws \Magento\Framework\Exception\NotFoundException
     */
    public function execute()
    {
        return $this->resultFactory->create(ResultFactory::TYPE_LAYOUT);
    }
}

レイアウト

<?xml version="1.0"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd">
    <container name="root">
        <block class="Namespace\Module\Block\Some\Block" name="namespace_module.some_block" />
    </container>
</layout>

Githubの例

このサンプルモジュールを参照してください:https : //github.com/herveguetin/Herve_AjaxLayout_M2

このモジュールはこれを生成します:

ここに画像の説明を入力してください


レイアウト全体をロードしたい場合(コンテナ、ブロックなどが少ないXML)作成-> toHtml、json経由でajaxに送信しますか?
mattkrupnik 2017

5

Magentoはそのままでは、これらのメソッドを使用せずにAJAX経由でHTMLをレンダリングします。

私が見てきたことから、そのようなことを行う必要があるたびに、JSONを使用して結果を転送します。

の例Magento/Checkout/Controller/Cart/Add

$this->getResponse()->representJson(
    $this->_objectManager->get('Magento\Framework\Json\Helper\Data')->jsonEncode($result)
);

次に、Magento 2はセクションと呼ばれる新しいメカニズムを使用して、フロントエンドのデータを処理し、更新が必要な特定のブロックを更新します。セクションについて詳しくは、このQ&Aをご覧くださいhttps : //magento.stackexchange.com/a/ 143381/2380

私の回答の2番目の部分に関する編集:コメントでMaxが述べたように、セクションは顧客固有のデータでのみ使用され、すべてのAJAX呼び出しの代わりにこの機能を使用することは適切なソリューションではありません。


はい、JSONを使用して結果を転送しますが、質問のためにクラスを簡略化します;)しかし、そのセクション機能を認識していません。それは、私が望むことを行う正しい方法のようです。見てみましょう。他の応答がある場合は待機します。それ以外の場合は、回答を検証します。ありがとう!
MatthéoGeoffray

2
生のHTMLデータの代わりにJson応答を使用することに同意します。しかし、あなたの答えの2番目の部分は完全に正しくはありません。顧客固有のデータにのみ使用し、すべてのAjax呼び出しの代わりにこの機能を使用する顧客セクションはお勧めできません。
最大

2
@Matthéoはい、私は理解しました:)回答の2番目の部分は他のユーザーに誤解されている可能性があるため、私のコメントは回答を修正するためにRaphaelに宛てられました。
最大

1
@MaxStsepantsevichそれを見つけてくれてありがとう、私はあなたの言ったことを反映するように私の答えを編集しました
デジタルピアニズムでのラファエル2017年

1
私はあなたのフィードバックを使用して回答を追加しました。助けてくれてありがとう。
MatthéoGeoffray

3

私の例では、/ アクションの後sectionsではないため、使用できませんが、回答を使用して、Magentoがセクションをレンダリングする方法を理解しました。 customer dataPUTPOSTRaphael at Digital Pianism

cartセクションの例を取り上げると、メソッド\Magento\Customer\CustomerData\SectionPool::getSectionDataByNamesを使用してセクションからデータを取得します。これ\Magento\Checkout\CustomerData\Cart::getSectionDataにより、セクションの領域を含む単一の配列が得られます。$this->layout->createBlock('Magento\Catalog\Block\ShortcutButtons')->toHtml()

これに応じて、ここに最終的なControllerクラスがあります。

<?php

namespace Foo\Bar\Controller\Popin;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Framework\Data\Form\FormKey\Validator;
use Psr\Log\LoggerInterface;

/**
 * Class Content
 */
class Content extends Action
{

    /**
     * @var LoggerInterface $logger
     */
    private $logger;
    /**
     * @var Validator $formKeyValidator
     */
    private $formKeyValidator;
    /**
     * @var JsonFactory $resultJsonFactory
     */
    private $resultJsonFactory;

    /**
     * Content constructor.
     *
     * @param Context $context
     * @param LoggerInterface $logger
     * @param Validator $formKeyValidator
     * @param JsonFactory $resultJsonFactory
     */
    public function __construct(
        Context $context,
        LoggerInterface $logger,
        Validator $formKeyValidator,
        JsonFactory $resultJsonFactory
    ) {
        $this->logger            = $logger;
        $this->formKeyValidator  = $formKeyValidator;
        $this->resultJsonFactory = $resultJsonFactory;
        parent::__construct($context);
    }

    /**
     *
     */
    public function execute()
    {
        if (!$this->formKeyValidator->validate($this->getRequest())) {
            return $this->resultRedirectFactory->create()->setPath('checkout/cart/');
        }

        /** @var \Magento\Framework\Controller\Result\Json $resultJson */
        $resultJson = $this->resultJsonFactory->create();

        try {
            /** @var \Magento\Framework\View\Layout $layout */
            $layout = $this->_view->getLayout();
            /** @var \Foo\Bar\Block\Popin\Content $block */
            $block = $layout->createBlock(\Foo\Bar\Block\Popin\Content::class);
            /** @var array $response */
            $response = [
                'content' => $block->toHtml(),
            ];
        } catch (\Exception $exception) {
            $resultJson->setStatusHeader(
                \Zend\Http\Response::STATUS_CODE_400,
                \Zend\Http\AbstractMessage::VERSION_11,
                'Bad Request'
            );
            /** @var array $response */
            $response = [
                'message' => __('An error occurred')
            ];
            $this->logger->critical($exception);
        }

        return $resultJson->setData($response);
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.