Magento 2 – Send Form Data to Controller Using AJAX and Return Result to PHTML

ajaxcontrollersmagento2module

I am working on a simple custom module, where user can input height and the weight/BMI will be shown as output on form submit. The page where user enters input is Calculation Page while output is shown on Result Page.On clicking the submit button user will be redirected to different controller/action. Below is the code

Calculation Layout – Vendor/Module/view/frontend/layout/module_index_index.xml

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">

    <head>
        <title>Calculator</title>
    </head> 

    <body>
        <referenceContainer name="content">
            <block class="Vendor\Module\Block\Index" name="calculation_index" template="Vendor_Module::calculation.phtml" />
        </referenceContainer>
    </body>
</page>

Calculation Input PHTML -Vendor/Module/view/frontend/templates/calculation.phtml

<div class="row clearfix">
        <div class="col-md-12 column">
            <form name="post-user-input" method="POST" id="height">
                  <div class="well">
                    <strong><?php echo __('Enter Height:')?></strong>
                    <input type="text" id="calculateTotalInput" name="calculateTotalInput" class="form-control input-md">
                    <input type="button" id="calculateTotalSubmit"  name="calculate-total-submit" value="Calculate Total">
                </div>

                <div class="col-sm-6 col-xs-12" style="margin-bottom: 30px;">
                    <?php echo __('Height:')?> <input type="text" value="<?= $weight ?>" name="height" class="form-control input-md" readonly="">
                    <?php echo __('BMI:')?> <input type="text" value="<?= $bmi ?>" name="weight" class="form-control input-md" readonly="">
                </div> 

            </form>
        </div>
    </div>


<script>
$(document).ready(function() {
    $("#height").submit(function(){
        jQuery.ajax({
        url: "/vendor/module/result/result",
        type: "POST",
        data: {height:height,weight:weight},
        success: function(response){
            console.log(response);
        }
    });
    });
});
</script>

Block – Vendor/Module/Block/Index.php

<?php

namespace Vendor\Module\Block;

use \Magento\Framework\View\Element\Template;
use \Magento\Framework\View\Element\Template\Context;

class Index extends Template
{

    public function __construct(Context $context,      
        \Magento\Store\Model\StoreManagerInterface $storeManager
    )
    {        
        $this->_storeManager = $storeManager;
        parent::__construct($context);
    }

    public function getBaseUrl()
    {
        return $this->_storeManager->getStore()->getBaseUrl();
    }

    public function getAjaxData()
    {
        return $this->getData();
    }
}

Calculation Controller – Vendor/Module/Controller/Index/Index.php

<?php

namespace Vendor\Module\Controller\Index;

use \Magento\Framework\App\Action\Action;
use \Magento\Framework\App\Action\Context;
use \Magento\Framework\View\Result\PageFactory;


class Index extends Action
{

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


    /**
    * Result constructor.
    * @param Context $context
    * @param PageFactory $pageFactory
    */
    public function __construct(Context $context, PageFactory $pageFactory)
    {
        $this->resultPageFactory = $pageFactory;
        parent::__construct($context);
    }


    /**
    * The controller action
    *
    * @return \Magento\Framework\View\Result\Page
    */
    public function execute()
    {
        $resultPage = $this->resultPageFactory->create();
        return $resultPage;
    }
}

Result Page Controller – Vendor/Module/Controller/Result/Result.php

<?php

namespace Vendor\Module\Controller\Result;

use Magento\Framework\App\Action\Context;
use Magento\Framework\View\Result\PageFactory;
use Magento\Framework\Controller\Result\JsonFactory;

class Result extends \Magento\Framework\App\Action\Action
{

     /**
     * @var Magento\Framework\View\Result\PageFactory
     */
    protected $resultPageFactory;

    protected $resultJsonFactory; 

    /**
     * @param Context     $context
     * @param PageFactory $resultPageFactory
     */
    public function __construct(
        Context $context,
        PageFactory $resultPageFactory,
        JsonFactory $resultJsonFactory
        )
    {

        $this->resultPageFactory = $resultPageFactory;
        $this->resultJsonFactory = $resultJsonFactory; 
        parent::__construct($context);
    }


    public function execute()
    {
        $data = $this->getRequest()->getParam('data');
        $result = $this->resultJsonFactory->create();
        $resultPage = $this->resultPageFactory->create();

        $block = $resultPage->getLayout()
                ->createBlock('Vendor\Module\Block\Index')
                ->setTemplate('Vendor_Module::result.phtml')
                ->setData('data',$data)
                ->toHtml();

        $result->setData(['output' => $block]);
        return $result;
    } 
}

Result Layout File – Vendor/Module/view/frontend/layout/module_result_result.xml

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">

    <head>
        <title>Result</title>
    </head> 

    <body>
        <referenceContainer name="content">
            <block class="Vendor\Module\Block\Index" name="calculation_result" template="Vendor_Module::result.phtml" />
        </referenceContainer>
    </body>
</page>

Result PHTML file – Vendor/Module/view/frontend/templates/result.phtml

<?php 

    echo $block->getAjaxData();

?>

The workflow – user comes on calculation.phtml page > enters input >
call result ctrl via ajax on button submit > process data in result
ctrl > show the data in updated result.html with page reload.

  • While trying to call controller action using AJAX, it is not working.
    How do I call and pass data to controller via AJAX ?
  • How do I return data from controller in JSON format and send it back
    to result.phtml file in order to show the output ?

Best Answer

Calculation Layout -

Vendor/Module/view/frontend/layout/module_index_index.xml

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <title>Calculator</title>
    </head> 
    <body>
        <referenceContainer name="content">
            <block class="Vendor\Module\Block\Index" name="calculation_index" template="Vendor_Module::calculation.phtml" />
        </referenceContainer>
    </body>
</page>

Calculation Input PHTML -

Vendor/Module/view/frontend/templates/calculation.phtml

<div class="row clearfix">
        <div class="col-md-12 column">
            <form name="form_height" method="POST" id="form_height">
                    <input type="text" name="height" class="form-control input-md">
                    <input type="text" name="weight" class="form-control input-md">
                    <input type="submit" id="calculateTotalSubmit"  name="calculate-total-submit" value="Calculate Total">
                </div> 
            </form>
        </div>
    </div>


<script>
require(['jquery'],function(){
    jQuery(document).ready(function() {
        jQuery("#form_height").submit(function(){

            var heightValue = jQuery("input[name='height']").val();
            var weightValue = jQuery("input[name='weight']").val();

            var url = "<?php echo $block->getBaseUrl().'module/result/result/' ?>";
            jQuery.ajax({
            url: url,
            type: "POST",
            data: {height:heightValue,weight:weightValue},
            showLoader: true,
            cache: false
            success: function(response){
                console.log(response.output);
            }
        });
        return false;
        });
    });
});
</script>

Block -

Vendor/Module/Block/Index.php

<?php

namespace Vendor\Module\Block;

use \Magento\Framework\View\Element\Template;
use \Magento\Framework\View\Element\Template\Context;

class Index extends Template
{

    public function __construct(Context $context,      
        \Magento\Store\Model\StoreManagerInterface $storeManager
    )
    {        
        $this->_storeManager = $storeManager;
        parent::__construct($context);
    }

    public function getBaseUrl()
    {
        return $this->_storeManager->getStore()->getBaseUrl();
    }

    public function getHeightData()
    {
        return $this->getHeight();
    }

    public function getWeightData()
    {
        return $this->getWeight();
    }
}

Calculation Controller -

Vendor/Module/Controller/Index/Index.php

<?php

namespace Vendor\Module\Controller\Index;

use \Magento\Framework\App\Action\Action;
use \Magento\Framework\App\Action\Context;
use \Magento\Framework\View\Result\PageFactory;


class Index extends Action
{

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


    /**
    * Result constructor.
    * @param Context $context
    * @param PageFactory $pageFactory
    */
    public function __construct(Context $context, PageFactory $pageFactory)
    {
        $this->resultPageFactory = $pageFactory;
        parent::__construct($context);
    }


    /**
    * The controller action
    *
    * @return \Magento\Framework\View\Result\Page
    */
    public function execute()
    {
        $resultPage = $this->resultPageFactory->create();
        return $resultPage;
    }
}

Result Page Controller -

Vendor/Module/Controller/Result/Result.php

<?php

namespace Vendor\Module\Controller\Result;

use Magento\Framework\App\Action\Context;
use Magento\Framework\View\Result\PageFactory;
use Magento\Framework\Controller\Result\JsonFactory;

class Result extends \Magento\Framework\App\Action\Action
{

     /**
     * @var Magento\Framework\View\Result\PageFactory
     */
    protected $resultPageFactory;

    protected $resultJsonFactory; 

    /**
     * @param Context     $context
     * @param PageFactory $resultPageFactory
     */
    public function __construct(
        Context $context,
        PageFactory $resultPageFactory,
        JsonFactory $resultJsonFactory
        )
    {

        $this->resultPageFactory = $resultPageFactory;
        $this->resultJsonFactory = $resultJsonFactory; 
        return parent::__construct($context);
    }


    public function execute()
    {
        $height = $this->getRequest()->getParam('height');
        $weight = $this->getRequest()->getParam('weight');
        $result = $this->resultJsonFactory->create();
        $resultPage = $this->resultPageFactory->create();

        $block = $resultPage->getLayout()
                ->createBlock('Vendor\Module\Block\Index')
                ->setTemplate('Vendor_Module::result.phtml')
                ->setData('height',$height)
                ->setData('weight',$weight)
                ->toHtml();

        $result->setData(['output' => $block]);
        return $result;
    } 
}

Result Layout File -

Vendor/Module/view/frontend/layout/module_result_result.xml

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <title>Result</title>
    </head> 
    <body>
        <referenceContainer name="content">
            <block class="Vendor\Module\Block\Index" name="result_result" template="Vendor_Module::result.phtml" />
        </referenceContainer>
    </body>
</page>

Result PHTML file -

Vendor/Module/view/frontend/templates/result.phtml

<?php 

    echo $block->getHeightData();
    echo $block->getWeightData();

?>