8

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 ?

3 Answers 3

16

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

?>
11
  • How initial HTML will be called as I have mentioned in my question with code snippet ? The workflow - user comes on calculation page > enters input > call ctrl via ajax on button submit > process data > show the data in updated html with page reload. Oct 9, 2017 at 11:49
  • See custom.phtml file in my answer. You can call your html code in that file. and you can show response using <?php echo $block->getAjaxData(); ?> in this file. Oct 9, 2017 at 11:52
  • Sorry it was my mistake. I have updated my answer. Your initial file will be initial.phtml. Oct 9, 2017 at 12:25
  • You ajax call will start from initial.phtml file, then it will send ajax data to index controller. The controller file will send data to custom.phtml and the data of custom.phtml file will go back to your initial.phtml file through the controller in json format. Oct 9, 2017 at 12:32
  • Changed the code, but still getting this error - Fatal error: Uncaught TypeError: Argument 3 passed to Vendor\Module\Controller\Index\Index::__construct() must be an instance of Magento\Framework\Controller\Result\JsonFactory Oct 9, 2017 at 12:36
1

Accepted Answer has Error:

Uncaught SyntaxError: Unexpected identifier

just replace javascript code with the following snippet in the file:

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

<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>
0

Anyone who is looking for the answer one can follow this tutorial, very much helpful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.