How To use RequireJS and Ajax in Magento 2 Extension

I have introduced How to get Items to frontend in Magento 2 extension in previous post so you can have an simple extension now . When you building Magento extension , you have to jquery and ajax to build separate function. If you can use Jquery like simple html in magento but in Magento you should not use it . Magento 2 use RequireJS so I will introduce How To use RequireJS and Ajax in Magento 2 Extension . 
in the post I will do :

  • Add new field number_vote to database .
  • Use RequireJS and ajax
  • Create Vote Controller

1. Add new field number_vote to database

As you know, I have introduce How to get Items to frontend in Magento 2 extension .

How To use RequireJS and Ajax in Magento 2 Extension

In order to introduce RequireJS and ajax, I will add new field number_vote and show it to frontend.

  • Update UpdateScript in file app/code/Magebay/Hello/Setup/UpgradeSchema.php and increase version 2.1.8 in
    app/code/Magebay/Hello/etc/module.xml
<?php 

namespace Magebay\Hello\Setup;
//.. old code 
class UpgradeSchema implements  UpgradeSchemaInterface
{
    /**
     * @param SchemaSetupInterface $setup
     * @param ModuleContextInterface $context
     * @throws \Zend_Db_Exception
     */
    public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context){
        $setup->startSetup();
	// old code 
        if (version_compare($context->getVersion(), '2.1.8') < 0) {
            $table = $setup->getTable('magebay_news');
            if ($setup->getConnection()->isTableExists($table) == true) {
                // Declare data
                $columns = [
                    'number_vote' => [
                        'type' => \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
                        ['nullable' => true, 'default' => 0],
                        'comment' => 'Vote ',
                    ],
                ];
                $connection = $setup->getConnection();
                foreach ($columns as $name => $definition) {
                    $connection->addColumn($table, $name, $definition);
                }
            }
        }
        $setup->endSetup();
    }
}
  • Next ,you run command php bin/magento setup:upgrade and edit block to show it frontend. You can update file
    app/code/ Magebay/Hello/Block/Posts.php and app/code/Magebay/Hello/Block/view/frontend/posts/item.phml
<?php
#file Magebay/Hello/Block/Posts.php
namespace Magebay\Hello\Block;

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

/**
 * Class Posts
 * @package Magebay\Hello\Block
 */
class Posts extends Template
{
    // ..old code ..
    function getPostItems() {
        if($this->coreRegistry->registry('post_items'))
        {
            $collection = $this->coreRegistry->registry('post_items');
        }
        else {
            $collection = $this->postsFactory->create()
                ->addFieldToSelect(array('title','description','number_vote')) // add number_vote to filter
                ->addFieldToFilter('status',1)
                ->setPageSize(10)
                ->setOrder('position','ASC');
            $this->coreRegistry->register('post_items',$collection);
        }
        return $collection;

    }
    
}
<!--old code -->
<div class="post-content">
    <table style="width:100%">
        <tr>
            <!--old code -->
            <th><?php echo __('Number Vote') ?></th>
            <th><?php echo __('Vote') ?></th>
        </tr>
        <?php if(count($posts)) : ?>
                <?php foreach ($posts as $post) : ?>
                   <tr>
                       <!--old code -->
                       <td><span id="post-item-vote-<?php echo $post->getId(); ?>"><?php echo $post->getNumberVote() ?></span></td>
                       <td><a href="#" id="post-item-<?php echo $post->getId() ?>" class="post-item"><?php echo __('Vote'); ?></a> </td>
                   </tr>
                <?php endforeach; ?>
        <?php endif; ?>
    </table>
</div>

You will see list will be updated in frontend.

How To use RequireJS and Ajax in Magento 2 Extension

2.Use RequireJS and ajax

After adding new field number_vote and show it list, I will use RequireJS and Ajax that allow customer can vote for each item list.
Under List post in file
app/code/Magebay/Hello/Block/view/frontend/posts/item.phml add code bellow :

<input type="hidden" id="vote-url" value="<?php echo $block->getUrl('hello/index/vote') ?>">
<script>
    require([
        'jquery',
        'Magento_Ui/js/modal/alert'
    ],function ($,alert) {
        postItem = {
            version: '2.1.8',
            vote_url : '',
            vote: function (postId) {
                console.log('Post Id'+postId)
                var self = this;
                $.ajax({
                    url : self.vote_url,
                    dataType: 'json',
                    type: 'POST',
                    data : {post_id: postId},
                    success : function (response) {
                        if(response.status === 'success')
                        {
                            $('#post-item-vote-'+postId).html(response.new_vote)
                            alert({
                                title : 'Success',
                                content :'You have voted successfully!'
                            })
                        }
                    },
                    error : function () {
                        alert({
                            title : 'Success',
                            content :'Error, Please try again !'
                        })
                    }
                })
            },
            init : function () {
                var self = this;
                self.vote_url = $("#vote-url").val();
                $('.post-item').click(function () {
                    var postId = $(this).attr('id');
                    postId = postId.replace('post-item-','');
                    self.vote(postId)
                })
            }
        }
        postItem.init();
    })
</script>

3. Create Vote Controller

As you can see I have create an Url hello/index/vote so I will create a Controller that can update vote when customer clicking to vote in list . Create file app/code/Magebay/Hello/Controller/Index/Vote.php

<?php
/**
 * Created by PhpStorm.
 * User: maiuoc
 * Date: 2019-01-22
 * Time: 9:36 AM
 */

namespace Magebay\Hello\Controller\Index;

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

/**
 * Class Vote
 * @package Magebay\Hello\Controller\Index
 */
class Vote extends \Magento\Framework\App\Action\Action
{
    /**
     * @var \Magento\Framework\Controller\Result\JsonFactory
     */
    protected $jsonFactory;
    /**
     * @var \Magebay\Hello\Model\PostsFactory
     */
    protected $postsFactory;
    /**
     * @var \Magebay\Hello\Model\ResourceModel\PostsFactory
     */
    protected $resPostsFactory;

    /**
     * Vote constructor.
     * @param Context $context
     * @param PageFactory $resultPageFactory
     * @param \Magento\Framework\Controller\Result\JsonFactory $jsonFactory
     * @param \Magebay\Hello\Model\PostsFactory $postsFactory
     * @param \Magebay\Hello\Model\ResourceModel\PostsFactory $resPostsFactory
     */
    public function __construct(
        Context $context,
        PageFactory $resultPageFactory,
        \Magento\Framework\Controller\Result\JsonFactory $jsonFactory,
        \Magebay\Hello\Model\PostsFactory $postsFactory,
        \Magebay\Hello\Model\ResourceModel\PostsFactory $resPostsFactory
    )
    {
        parent::__construct($context);
        $this->resultPageFactory = $resultPageFactory;
        $this->jsonFactory = $jsonFactory;
        $this->postsFactory = $postsFactory;
        $this->resPostsFactory = $resPostsFactory;

    }

    /**
     * @return $this|\Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $postId = $this->getRequest()->getParam('post_id',0);
        $response = array(
          'status'=>'error',
          'message'=>'Error',
          'new_vote'=>0
        );
        if((int)$postId > 0)
        {
            $postModel = $this->postsFactory->create();
            $resPostModel = $this->resPostsFactory->create();
            // get current vote
            $resPostModel->load($postModel,$postId);
            if($postModel &amp;&amp; $postModel->getId())
            {
                $curVote = $postModel->getData('number_vote');
                $curVote++;
                $postModel->setData('number_vote',$curVote);
                try {
                    $resPostModel->save($postModel);
                    $response['status'] = 'success';
                    $response['message'] = 'success';
                    $response['new_vote'] = $curVote;
                }
                catch (\Exception $exception)
                {

                }
            }
        }
        return $this->jsonFactory->create()->setData($response);
    }
}

Now, number votes will be updated when custom click vote for each item in list.

How To use RequireJS and Ajax in Magento 2 Extension

Well, I have done the most basic issues about How to build Magento 2 extension . If you want to build an extension by your self, you can read tutorial , it is more simple if you do step by step like me. If you have an any ideal about Magento 2 extension , you can comment under this post. I hope you will build great Magento 2 extension for your website and Project,