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 모범 사례 는 컨트롤러와 로직을 분리하기 때문에 Way 2로 보입니다 .
그러나의 문제 방법 2 이다 <body><head>함께이 CSS/ JS그것의 단지 내 블록 템플릿 전체 청소 HTML되지 않도록 생성됩니다.

  • 사용자 정의 레이아웃을 잘못 사용하고 있습니까?
  • 는 IS 방법 (1) 좋은 연습으로 간주됩니다?
  • 다른 방법이 있습니까?

답변:


18

나는 또한 2 길을 가고 실제로 머리, 몸통, CSS 등없이 AJAX를 통해 "순수한"HTML을 렌더링 할 수 있습니다.

비결은 다음과 같습니다.

  • 컨트롤러에게 유형이 \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

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에서 섹션에 대해 자세히 알아볼 수 있습니다. /magento//a/ 143381/2380

내 답변의 두 번째 부분에 대한 편집 : 의견에서 Max가 언급했듯이 섹션은 고객 특정 데이터에만 사용되며 모든 AJAX 호출 대신이 기능을 사용하는 것이 올바른 해결책은 아닙니다.


예, JSON을 사용하여 결과를 전송하지만 질문의 목적으로 클래스를 단순화합니다.)하지만 해당 섹션 기능을 알지 못하므로 원하는 것을 수행하는 올바른 방법 인 것 같습니다. 나는 그것을 볼 것이다. 다른 답변이 있으면 기다립니다. 그렇지 않으면 답변을 확인하겠습니다. 감사 !
Matthéo Geoffray

2
원시 html 데이터 대신 Json 응답을 사용하는 데 동의합니다. 그러나 답의 두 번째 부분은 정확하지 않습니다. 고객 별 데이터에만 사용하고 모든 Ajax 호출 대신이 기능을 사용하는 고객 섹션은 좋은 생각이 아닙니다.
Max

2
@ Matthéo 예, 이해했습니다 :) 답변의 두 번째 부분은 다른 사용자가 오해 할 수 있기 때문에 내 의견은 답변을 수정하기 위해 Raphael에게 전달되었습니다.
Max

1
@MaxStsepantsevich 감사합니다. 귀하의 의견을 반영하기 위해 답변을 편집했습니다.
Digital Pianism의 Raphael

1
피드백을 사용하여 답변을 추가했습니다. 도와 주셔서 감사합니다.
Matthéo Geoffray

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()

여기에 따라 최종 컨트롤러 클래스가 있습니다.

<?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.