How to Load Custom Collection Data Using Ajax in Magento 2

ajaxcms-blockfrontendmagento2

I want to display modal collection data using load more Ajax functionality, currently i am display load more data using jquery & CSS.

Because for now i have a limited collection data but in future collection data size will be bigger and bigger then it will be take more time to load.

so i want to display data using Ajax, first it will display 3 row and when i click on load more then it will load more 3 row, how can i achieve this thing.

Namespace\ModuleName\Block\Producer\MeetOurProducer.php

/**
 * @var \RB\producer\Model\producerWebsiteFactory
 */
private $producerWebsiteFactory;

public function _prepareLayout()
{
    parent::_prepareLayout();
}

public function __construct(
\Magento\Framework\View\Element\Template\Context $context, \RB\producer\Model\producerWebsiteFactory $producerWebsiteFactory, array $data = array()
)
{
    $this->_storeManagerInterface = $context->getStoreManager();

    parent::__construct($context, $data);
    $this->producerWebsiteFactory = $producerWebsiteFactory;
}

public function getproducerCollection()
{
    $lastId = $this->getRequest()->getParam('last_producer_id');
    //echo $lastId;die('CP');
    $store = $this->_storeManagerInterface->getStore();
    $collections = $this->producerWebsiteFactory->create()
        ->getCollection()
        ->addFieldToFilter('status', array(['eq' => producerStatus::producer_STATUS_ACTIVE], ['eq' => producerStatus::producer_STATUS_VACATION_MODE]))
        ->addFieldToFilter('website_id', ['eq' => $store->getWebsiteId()]);

    $collections->getSelect()->joinLeft(['rb_producer_microsites' => $collections->getTable('rb_producer_microsites')],
                                                                                            'main_table.producer_id = rb_producer_microsites.producer_id AND rb_producer_microsites.store_id =' . $store->getStoreId());

    return $collections;
}

Namespace\ModuleName\Block\Producer\MeetOurProducer.phtml

<div class="producer-list">
<ul id="our_producers">
    <?php foreach($vendors as $vendor) { ?>
    <li>
        <div class="vendor-image">
            <?php if (!empty($vendor->getLogo()) && $helper->isImageExist($block->getMediaUrlSellerDirectory() . 'vendor/logo' . $vendor->getLogo())) : ?>
                <img src="<?php echo $helper->resize($vendor->getLogo(), 'vendor/logo', null, 200); ?>" />
            <?php else: ?>
                <img src="<?php echo $this->getViewFileUrl('Namespace_Modulename::images/small_image.png'); ?>" />
            <?php endif; ?>
        </div>
        <div class="vendor-content">
            <h3><?php echo $vendor->getBusinessName(); ?></h3>
            <p><?php 
                $in = $vendor->getShortDescription(); 
                $out = strlen($in) > 360 ? substr($in,0,360)."..." : $in;
                echo $out;
                ?></p>
            <?php if(!empty($vendor->getUrlKey()) && $vendor->getGoLive() != 0) { ?>
            <div class="actions">
                <a class="action btn" href="<?php echo $block->getStoreUrl(); echo $vendor->getUrlKey();?>"><?php echo __('VIEW PRODUCTS'); ?></a>
            </div>
            <?php } ?>
        </div>
    </li>
    <?php } ?>
</ul>
<div class="actions" id="remove_row">
    <button id="our_producers_show_more" id="btn_more" class="our-producers-show-more"><?php echo __('LOAD MORE'); ?></button>
</div>

And i call this block to admin block

{{block class="Namespace\Modulename\Block\Producer\MeetOurProducer" template="Namespace_Modulename::producer/meetourproducer.phtml"}}

Any help would be appreciated. Thanks.

Best Answer

I found the solution.

Step 1. Create block file

Namespace\ModuleName\Block\Producer\MeetOurProducer.php

/**
 * @var \RB\producer\Model\producerWebsiteFactory
 */
private $producerWebsiteFactory;

public function _prepareLayout()
{
    parent::_prepareLayout();
}

public function __construct(
\Magento\Framework\View\Element\Template\Context $context, \RB\producer\Model\producerWebsiteFactory $producerWebsiteFactory, array $data = array()
)
{
    $this->_storeManagerInterface = $context->getStoreManager();

    parent::__construct($context, $data);
    $this->producerWebsiteFactory = $producerWebsiteFactory;
}

public function getproducerCollection()
{
    $lastId = $this->getRequest()->getParam('last_producer_id');

    $store = $this->_storeManagerInterface->getStore();
    $collections = $this->producerWebsiteFactory->create()
        ->getCollection()
        ->addFieldToFilter('status', array(['eq' => producerStatus::producer_STATUS_ACTIVE], ['eq' => producerStatus::producer_STATUS_VACATION_MODE]))
        ->addFieldToFilter('website_id', ['eq' => $store->getWebsiteId()]);

    $collections->getSelect()->joinLeft(
        ['rb_producer_microsites' => $collections->getTable('rb_producer_microsites')],
                                                          'main_table.producer_id = rb_producer_microsites.producer_id AND rb_producer_microsites.store_id =' . $store->getStoreId());
    $collections->getSelect()->order('producer_website_id', 'ASC');
    if ($lastId && $lastId != null) {
        $collections->addFieldToFilter('producer_website_id', array('gt' => $lastId));
    }
    $collections->getSelect()->limit(3);
    return $collections;
}

Step 2. Create phtml to render layout.

Namespace\ModuleName\View\Frontend\template\producer\meetourproducer.html

<?php if (count($vendors) > 0) { ?>
<div class="producer-list">
    <ul id="our_producers">

        <?php
        foreach ($vendors as $vendor) :
            $vendorWebsiteId = $vendor['vendor_website_id'];
            ?>
            <li id="our_producers-li">
                <div class="vendor-image">
                    <?php if (!empty($vendor->getLogo()) && $helper->isImageExist($block->getMediaUrlSellerDirectory() . 'vendor/logo' . $vendor->getLogo())) : ?>
                        <img src="<?php echo $helper->resize($vendor->getLogo(), 'vendor/logo', null, 200); ?>" />
                    <?php else: ?>
                        <img src="<?php echo $this->getViewFileUrl('RBC_Vendorvalue::images/small_image.png'); ?>" />
                    <?php endif; ?>
                </div>
                <div class="vendor-content">
                    <h3><?php echo $vendor->getBusinessName(); ?></h3>
                    <p><?php
                        $in = $vendor->getShortDescription();
                        $out = strlen($in) > 360 ? substr($in, 0, 360) . "..." : $in;
                        echo $out;
                        ?></p>
                    <?php if (!empty($vendor->getUrlKey()) && $vendor->getGoLive() != 0) { ?>
                        <div class="actions">
                            <a class="action btn" href="<?php
                            echo $block->getStoreUrl();
                            echo $vendor->getUrlKey();
                            ?>"><?php echo __('VIEW PRODUCTS'); ?></a>
                        </div>
                    <?php } ?>
                </div>
            </li>

            <?php
            $lastVendorWebsiteId = $vendorWebsiteId;
        endforeach;
        ?>
    </ul>
    <div class="actions" id="remove_row">
        <button id="our_producers_show_more_1" class="our-producers-show-more" data-pid="<?php echo $lastVendorWebsiteId; ?>"><?php echo __('LOAD MORE'); ?></button>
    </div>
</div>
<?php } ?>

<script type="text/javascript">
require(['jquery',
], function ($) {
    $(document).ready(function () {
        $(document).on('click', '#our_producers_show_more_1', function () {
            var last_producer_id = $(this).data("pid");
            $('#our_producers_show_more_1').html("Loading...");
            $.ajax({
                url: "rbvendor/producer/meetourproducer",
                method: "POST",
                data: {last_producer_id: last_producer_id},
                dataType: "json",
                success: function (data)
                {
                    $('#our_producers_show_more_1').html("LOAD MORE");
                    if (data != '')
                    {
                        $('#our_producers').append(data);
                    } else
                    {
                        $('#our_producers_show_more_1').html("No Data");
                        $('#remove_row').remove();
                    }
                }
            });
        });
    });
});
</script>

Step 3. Create ajax phtml to load html on click load more.

Namespace\ModuleName\View\Frontend\template\producer\ajaxmeetourproducer.html

<?php if (count($vendors) > 0) { ?>
<?php
foreach ($vendors as $vendor) :
    $vendorWebsiteId = $vendor['vendor_website_id'];
    ?>
    <li id="our_producers-li">
        <div class="vendor-image">
            <?php if (!empty($vendor->getLogo()) && $helper->isImageExist($block->getMediaUrlSellerDirectory() . 'vendor/logo' . $vendor->getLogo())) : ?>
                <img src="<?php echo $helper->resize($vendor->getLogo(), 'vendor/logo', null, 200); ?>" />
            <?php else: ?>
                <img src="<?php echo $this->getViewFileUrl('RBC_Vendorvalue::images/small_image.png'); ?>" />
            <?php endif; ?>
        </div>
        <div class="vendor-content">
            <h3><?php echo $vendor->getBusinessName(); ?></h3>
            <p><?php
                $in = $vendor->getShortDescription();
                $out = strlen($in) > 360 ? substr($in, 0, 360) . "..." : $in;
                echo $out;
                ?></p>
            <?php if (!empty($vendor->getUrlKey()) && $vendor->getGoLive() != 0) { ?>
                <div class="actions">
                    <a class="action btn" href="<?php
                       echo $block->getStoreUrl();
                       echo $vendor->getUrlKey();
                       ?>"><?php echo __('VIEW PRODUCTS'); ?></a>
                </div>
                <?php
            }
            $lastVendorWebsiteId = $vendorWebsiteId;
            ?>
        </div>

        <script type="text/javascript">
            require(['jquery',
            ], function ($) {
                $(document).ready(function () {
                    $('#our_producers_show_more_1').data("pid", <?php echo $lastVendorWebsiteId; ?>);
                });
            });
        </script>
    </li>
    <?php endforeach; ?>    

Step 4. Create controller to define block & ajax phtml.

Namespace\ModuleName\Controler\Producer\MeetOurProducer.php

/**
 * @var \RB\Vendor\Model\Design
 */
private $design;

/**
 * @var PageFactory
 */
protected $resultPageFactory;

/**
 * @var \Magento\Framework\UrlInterface 
 */
protected $urlModel;

/**
 * @param Context $context
 * @param \RB\Vendor\Model\Design $design
 * @param PageFactory $resultPageFactory
 */
public function __construct(
    Context $context, 
    \RB\Vendor\Model\Design $design, 
    UrlFactory $urlFactory, 
    PageFactory $resultPageFactory,
    \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory,
    \Magento\Framework\View\Result\LayoutFactory $resultLayoutFactory

) {        
    $this->resultPageFactory = $resultPageFactory;
    $this->resultJsonFactory = $resultJsonFactory;
    $this->_resultLayoutFactory = $resultLayoutFactory;
    $this->urlModel = $urlFactory->create();
    $this->design = $design;

    parent::__construct($context);
}


public function execute()
{
   $result =  $this->_resultLayoutFactory->create();
   $response =  $this->resultJsonFactory->create();
   $resultPage = $this->resultPageFactory->create();
    if ($this->getRequest()->isAjax()) 
    {
        $block = $resultPage->getLayout()
            ->createBlock('Namespace\Modulename\Block\Producer\MeetOurProducer')
            ->setTemplate('Namespace_Modulename::producer/ajaxmeetourproducer.phtml')
            ->toHtml();

        $response->setData($block);
        return $response;
    }
}

And i call this block to admin block

{{block class="Namespace\Modulename\Block\Producer\MeetOurProducer" template="Namespace_Modulename::producer/meetourproducer.phtml"}}