How to Make an Ajax Call in Magento 2 Module

In this article, we are going to understand and implement how to make an ajax call in Magento 2 Module. We will override the Magento 2 Contact us module to submit the contact form data using an ajax call. We will override the contact us module frontend PHTML file and Post Controller in our custom module.

On successful ajax call, we will return a success message from the controller. That message we will display on front side. You can also return the whole HTML using Ajax call.

Getting Started: Development

Step 1: Create module.xml file under app/code/Codextblog/Contactajax/etc directory

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd">
    <module name="Codextblog_Contactajax" setup_version="1.0.0"></module>
        <sequence>
            <module name="Magento_Contact"/>
        </sequence>
</config>

Step 2: Create registration.php file under app/code/Codextblog/Contactajax

<?php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Codextblog_Contactajax',
    __DIR__
    );

Step 3: Override contact_index_index.xml layout file in our module under app/code/Codextblog/Contactajax/view/frontend/layout directory

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <referenceBlock name='contactForm'>
    	<action method='setTemplate'>
        <argument name='template' xsi:type='string'>Codextblog_Contactajax::form.phtml</argument>
    	</action>
    </referenceBlock>
</page>

Step 4: Override form.phtml template file under app/code/Codextblog/Contactajax/view/frontend/templates directory

<?php

/**
 * Copyright © 2013-2017 Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
?>
<form class="form contact"
      action="<?php /* @escapeNotVerified */ echo $block->getFormAction(); ?>"
      id="contact-form"
      method="post"
      data-hasrequired="<?php /* @escapeNotVerified */ echo __('* Required Fields') ?>"
>
    <fieldset class="fieldset">
        <legend class="legend"><span><?php /* @escapeNotVerified */ echo __('Write Us') ?></span></legend><br />
        <div class="field note no-label"><?php /* @escapeNotVerified */ echo __('Jot us a note and we’ll get back to you as quickly as possible.') ?></div>
        <div class="field name required">
            <label class="label" for="name"><span><?php /* @escapeNotVerified */ echo __('Name') ?></span></label>
            <div class="control">
                <input name="name" id="name" title="<?php /* @escapeNotVerified */ echo __('Name') ?>" value="<?php echo $block->escapeHtml($this->helper('Magento\Contact\Helper\Data')->getPostValue('name') ?: $this->helper('Magento\Contact\Helper\Data')->getUserName()) ?>" class="input-text" type="text" data-validate="{required:true}"/>
            </div>
        </div>
        <div class="field email required">
            <label class="label" for="email"><span><?php /* @escapeNotVerified */ echo __('Email') ?></span></label>
            <div class="control">
                <input name="email" id="email" title="<?php /* @escapeNotVerified */ echo __('Email') ?>" value="<?php echo $block->escapeHtml($this->helper('Magento\Contact\Helper\Data')->getPostValue('email') ?: $this->helper('Magento\Contact\Helper\Data')->getUserEmail()) ?>" class="input-text" type="email" data-validate="{required:true, 'validate-email':true}"/>
            </div>
        </div>
        <div class="field telephone">
            <label class="label" for="telephone"><span><?php /* @escapeNotVerified */ echo __('Phone Number') ?></span></label>
            <div class="control">
                <input name="telephone" id="telephone" title="<?php /* @escapeNotVerified */ echo __('Phone Number') ?>" value="<?php echo $block->escapeHtml($this->helper('Magento\Contact\Helper\Data')->getPostValue('telephone')) ?>" class="input-text" type="text" />
            </div>
        </div>
        <div class="field comment required">
            <label class="label" for="comment"><span><?php /* @escapeNotVerified */ echo __('What’s on your mind?') ?></span></label>
            <div class="control">
                <textarea name="comment" id="comment" title="<?php /* @escapeNotVerified */ echo __('What’s on your mind?') ?>" class="input-text" cols="5" rows="3" data-validate="{required:true}"><?php echo $block->escapeHtml($this->helper('Magento\Contact\Helper\Data')->getPostValue('comment')) ?></textarea>
            </div>
        </div>
        <?php echo $block->getChildHtml('form.additional.info'); ?>
    </fieldset>
    <div class="actions-toolbar">
        <div class="primary">
            <input type="hidden" name="hideit" id="hideit" value="" />
            <button type="submit" title="<?php /* @escapeNotVerified */ echo __('Submit') ?>" class="action submit primary">
                <span><?php /* @escapeNotVerified */ echo __('Submit') ?></span>
            </button>
        </div>
    </div>
</form>
<?php 
$ajaxurl = $block->getFormAction();
?>
<script type="text/x-magento-init">
        {
            "*": {
                "Codextblog_Contactajax/js/contactajax": {
                    "AjaxUrl": "<?php echo $ajaxurl; ?>"
                }
            }
        }
</script>

Here we have removed the data-mage-init='{“validation”:{}}’ form attribute in line no 8. This attribute requires for form validation. We will define this validation in our custom js file in next step. We have added javascript call at the end of the file to include our custom js and pass an AjaxUrl as a parameter.

Make an Ajax Call

Step 5: Create contactajax.js file under app/code/Codextblog/Contactajax/view/frontend/web/js directory

define([
    "jquery",
    "jquery/ui"
], function($){
    "use strict";
    
    function main(config, element) {
    	var $element = $(element);
        var AjaxUrl = config.AjaxUrl;
        
        var dataForm = $('#contact-form');
        dataForm.mage('validation', {});
        
        $(document).on('click','.submit',function() {
        	
        	if (dataForm.valid()){
        	event.preventDefault();
                var param = dataForm.serialize();
                alert(param);
                    $.ajax({
                        showLoader: true,
                        url: AjaxUrl,
                        data: param,
                        type: "POST"
                    }).done(function (data) {
                    	$('.note').html(data);
                    	$('.note').css('color', 'red');
                    	document.getElementById("contact-form").reset();
                        return true;
                    });
        		}
            });
    };
return main;
    
    
});

Here we have defined the main function that is triggered whenever form.phtml file included in HTML. In line no 12, we have defined the validation. On form submit button if form validation is correct we are making an Ajax call to Contact Module Post.php controller. On an Ajax complete, we are printing the response and reset the form.

Override Controller

Step 6: Create di.xml file under app/code/Codextblog/Contactajax/etc directory with following content

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">

    <preference for="Magento\Contact\Controller\Index\Post" type="Codextblog\Contactajax\Controller\Magento\Contact\Index\Post" />
		
</config>

Step 7: Override Post.php controller file under app/code/Codextblog/Contactajax/Controller/Magento/Contact/Index directory

<?php

namespace Codextblog\Contactajax\Controller\Magento\Contact\Index;

use Magento\Framework\App\Request\DataPersistorInterface;
use Magento\Framework\App\ObjectManager;

class Post extends \Magento\Contact\Controller\Index\Post
{
	
	private $dataPersistor;
	
	public function execute()
	{
		
		$post = $this->getRequest()->getPostValue();
		
		if (!$post) {
			$this->_redirect('*/*/');
			return;
		}
		
		$this->inlineTranslation->suspend();
		try {
			$postObject = new \Magento\Framework\DataObject();
			$postObject->setData($post);
			
			$error = false;
			
			if (!\Zend_Validate::is(trim($post['name']), 'NotEmpty')) {
				$error = true;
			}
			if (!\Zend_Validate::is(trim($post['comment']), 'NotEmpty')) {
				$error = true;
			}
			if (!\Zend_Validate::is(trim($post['email']), 'EmailAddress')) {
				$error = true;
			}
			if (\Zend_Validate::is(trim($post['hideit']), 'NotEmpty')) {
				$error = true;
			}
			if ($error) {
				throw new \Exception();
			}
			
			$storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE;
			$transport = $this->_transportBuilder
			->setTemplateIdentifier($this->scopeConfig->getValue(self::XML_PATH_EMAIL_TEMPLATE, $storeScope))
			->setTemplateOptions(
					[
							'area' => \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE,
							'store' => \Magento\Store\Model\Store::DEFAULT_STORE_ID,
					]
					)
					->setTemplateVars(['data' => $postObject])
					->setFrom($this->scopeConfig->getValue(self::XML_PATH_EMAIL_SENDER, $storeScope))
					->addTo($this->scopeConfig->getValue(self::XML_PATH_EMAIL_RECIPIENT, $storeScope))
					->setReplyTo($post['email'])
					->getTransport();
					
					$transport->sendMessage();
					$this->inlineTranslation->resume();
					
					$message = __('Thanks for contacting us with your comments and questions. We\'ll respond to you very soon.');
							
					$this->getDataPersistor()->clear('contact_us');
					echo $message;
					//$this->_redirect('contact/index');
					return;
		} catch (\Exception $e) {
			$this->inlineTranslation->resume();
			$message = 
					__('We can\'t process your request right now. Sorry, that\'s all we know.');
					
			$this->getDataPersistor()->set('contact_us', $post);
			//$this->_redirect('contact/index');
			echo $message;
			return;
		}
	}
	
	private function getDataPersistor()
	{
		if ($this->dataPersistor === null) {
			$this->dataPersistor = ObjectManager::getInstance()
			->get(DataPersistorInterface::class);
		}
		
		return $this->dataPersistor;
	}
}		

Instead of redirecting to contact us page, we are printing success message and error message In line no 67 and 77. These messages are displayed at frontside in an ajax success call.

Run below command and check the contact us form by submitting it. On successful request, you will get the success message like below image.

magento_2_ajax_call_screenshot

 

php bin/magento setup:upgrade

php bin/magento setup:di:compile

php bin/magento setup:static-content:deploy

php bin/magento cache:clean

That’s It. We are done with submitting contact us form using an ajax call.

In the next article, we will see How to render an HTML using an Ajax call in Magento 2 Module.

If you liked this post, then please like us on Facebook and follow us on Twitter.

Want to ask a question or leave a comment?

Leave a Comment

(6 Comments)

  • Raj

    Hi, I am using Magento 2.3. I am getting an error”undefined properties _transportBuilder”.

    • Chirag

      Which Magento version are you using? Have you run setup upgrade command?

  • Brahmaiah

    which is not working. I am getting 404 Not Found error

  • Vrajesh

    Not working.

    • Admin

      What error are you getting? Please mentioned in the comment so others can help you to figure out your problem.

  • dhaval

    not working propare

  • All the comments are goes into moderation before approval. Irrelevant comment with links directly goes to spam. Your email address will not be published.

    Was this post helpful? Please support Us!

    Follow us on twitter or Like us on facebook.

     


    To Avoid Spam Downloads, We Want Your Email

    We will send you download link right
    away. Please submit form below.
    SEND ME DOWNLOAD LINK
    Close

    Increase Your
    Magento 2
    Knowledge

    Get Weekly Tutorial
    to your Inbox
    Subscribe Me
    close-link
    Subscribe Here