Magento2 | PWA | GraphQL

Magento2 Admin grid with product selection ui_component and display data with Knockout JS on frontend.


In this post we wiil check how to use admin UI component and display custom PHTML file on front end with the use of Knockout JS. And some other useful tips to display selection form of customers/products in the ui_component admin grid.

Also we will check how to display UI_Component grid on frontend.



.


Let's start it by creating custom extension. 

You can find complete module on Github at Magelearn_CodeSample

Create folder inside app/code/Magelearn/CodeSample

Add registration.php file in it:
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magelearn_CodeSample', __DIR__);
Add composer.json file in it:
{
    "name": "magelearn/module-codesample",
    "description": "Magento 2 CRUD and UiComponent form and grid using best practices in the adminhtml and frontend areas",
    "type": "magento2-module",
    "license": "GPL-3.0",
    "authors": [
        {
            "name": "Mage2Gen",
            "email": "info@mage2gen.com"
        },
        {
            "name": "vijay rami",
            "email": "vijaymrami@gmail.com"
        }
    ],
    "minimum-stability": "dev",
    "require": {},
    "autoload": {
        "files": [
            "registration.php"
        ],
        "psr-4": {
            "Magelearn\\CodeSample\\": ""
        }
    }
}
Add etc/module.xml file in it:
<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
	<module name="Magelearn_CodeSample" setup_version="1.0.0"/>
</config>
We will going to display our custom page on front end. That page serves data from database table.

So, first let's start by creating a db schema script for our custom table.

Create db_schema.xml file in etc folder.
here we will define property of all database fields and indexes. 
<?xml version="1.0" ?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
	<table name="magelearn_codesample" resource="default" engine="innodb" comment="Magelearn Codesample Table">
		<column xsi:type="smallint" name="entity_id" padding="6" unsigned="true" nullable="false" identity="true" comment="Entity Id"/>
		<constraint xsi:type="primary" referenceId="PRIMARY">
			<column name="entity_id"/>
		</constraint>
		<column name="product_ids" nullable="true" xsi:type="text" comment="Product ids" />
		<column name="additional_text" nullable="true" xsi:type="text" comment="Additional Text" />
		<index referenceId="MAGELEARN_CUSTOMFORM_PRODUCT_IDS" indexType="fulltext">
	        <column name="product_ids"/>
	    </index>
	    <index referenceId="MAGELEARN_CUSTOMFORM_ADDITIONAL_TEXT" indexType="fulltext">
	        <column name="additional_text"/>
	    </index>
	</table>
</schema>
To validate this db_schema.xml file we will first run below command:

php bin/magento setup:db-declaration:generate-whitelist --module-name=Magelearn_CodeSample

This command will automatically generate db_schema_whitelist.json file inside etc folder.

Now, we will add our Data patch file. This file will add some dummy data into database table.

Create CreateDefaultSamples.php file inside Setup/Patch/Data folder.

<?php

namespace Magelearn\CodeSample\Setup\Patch\Data;

use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;

class CreateDefaultSamples implements DataPatchInterface
{
    /**
     * @var ModuleDataSetupInterface
     */
    private $moduleDataSetup;

    public function __construct(
       ModuleDataSetupInterface $moduleDataSetup

     ) {

        $this->moduleDataSetup = $moduleDataSetup;

    }
    public function apply()
    {
        $this->moduleDataSetup->startSetup();
        $setup = $this->moduleDataSetup;

        $data = [
                [
                    'product_ids' => '',
                    'additional_text' => 'Text 1'
                ],
                [
                    'product_ids' => '',
                    'additional_text' => 'Text 2'
                ],
                [
                    'product_ids' => '',
                    'additional_text' => 'Text 3'
                ],
                [
                    'product_ids' => '',
                    'additional_text' => 'Text 4'
                ],
                [
                    'product_ids' => '',
                    'additional_text' => 'Text 5'
                ]
            ];

         $this->moduleDataSetup->getConnection()->insertArray(
            $this->moduleDataSetup->getTable('magelearn_codesample'),
            ['product_ids', 'additional_text'],
            $data
        );     
        $this->moduleDataSetup->endSetup();
    }
    public function getAliases()
    {
        return [];
    }
    public static function getDependencies()
    {
        return [];
    }
}

  • A data patch is a class that contains data modification instructions. It is defined in a <Vendor>/<Module_Name>/Setup/Patch/Data/<Patch_Name>.php file and implements \Magento\Framework\Setup\Patch\DataPatchInterface.
  • A schema patch contains custom schema modification instructions. These modifications can be complex. It is defined in a <Vendor>/<Module_Name>/Setup/Patch/Schema/<Patch_Name>.php file and implements \Magento\Framework\Setup\Patch\SchemaPatchInterface.
  • Unlike the declarative schema approach, patches will only be applied once. A list of applied patches is stored in the patch_list database table. An unapplied patch will be applied when running the setup:upgrade from the Magento CLI.
  • To define a dependency in a patch, add the method public static function getDependencies() to the patch class and return the class names of the patches this patch depends on. The dependency can be in any module.

To un-install our custom table and configuration options we will create Uninstall script.

Create Uninstall.php file inside Setup folder.

<?php

namespace Magelearn\CodeSample\Setup;

use Magento\Framework\Model\AbstractModel;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\Setup\UninstallInterface;
use Magento\Config\Model\ResourceModel\Config\Data;
use Magento\Config\Model\ResourceModel\Config\Data\CollectionFactory;

/**
 * Class Uninstall
 *
 * @package Magelearn\CodeSample\Setup
 */
class Uninstall implements UninstallInterface
{
    /**
     * @var CollectionFactory
     */
    protected $collectionFactory;
    /**
     * @var Data
     */
    protected $configResource;

    /**
     * @param CollectionFactory $collectionFactory
     * @param Data $configResource
     */
    public function __construct(
        CollectionFactory $collectionFactory,
        Data $configResource
    ) {
        $this->collectionFactory = $collectionFactory;
        $this->configResource    = $configResource;
    }

    /**
     * Drop sample table
     *
     * @param SchemaSetupInterface $setup
     * @param ModuleContextInterface $context
     */
    public function uninstall(SchemaSetupInterface $setup, ModuleContextInterface $context)
    {
        if ($setup->tableExists('magelearn_codesample')) {
            $setup->getConnection()->dropTable('magelearn_codesample');
        }
        $collection = $this->collectionFactory->create()
            ->addPathFilter('Magelearn_CodeSample');
        foreach ($collection as $config) {
            $this->deleteConfig($config);
        }
    }

    /**
     * Delete system config
     *
     * @param AbstractModel $config
     */
    protected function deleteConfig(AbstractModel $config)
    {
        $this->configResource->delete($config);
    }
}

Now, create di.xml file inside etc folder. 

This file will define necessary nodes to display data in admin grid and save data.

<?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="Magelearn\CodeSample\Api\CodesampleRepositoryInterface" type="Magelearn\CodeSample\Model\CodesampleRepository"/>
	<preference for="Magelearn\CodeSample\Api\Data\CodesampleInterface" type="Magelearn\CodeSample\Model\Data\Codesample"/>
	<preference for="Magelearn\CodeSample\Api\Data\CodesampleSearchResultsInterface" type="Magento\Framework\Api\SearchResults"/>
	<virtualType name="Magelearn\CodeSample\Model\ResourceModel\Codesample\Grid\Collection" type="Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult">
		<arguments>
			<argument name="mainTable" xsi:type="string">magelearn_codesample</argument>
			<argument name="resourceModel" xsi:type="string">Magelearn\CodeSample\Model\ResourceModel\Codesample\Collection</argument>
		</arguments>
	</virtualType>
	<type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
		<arguments>
			<argument name="collections" xsi:type="array">
				<item name="magelearn_codesample_listing_data_source" xsi:type="string">Magelearn\CodeSample\Model\ResourceModel\Codesample\Grid\Collection</item>
			</argument>
		</arguments>
	</type>
</config>

Now, We will define our frontend routes.
Create routes.xml file inside etc/frontend folder. 

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="standard">
        <route frontName="codesample" id="codesample">
            <module name="Magelearn_CodeSample"/>
        </route>
    </router>
</config>
Now, Its turn to create Block, Controller, Layout and Template files.
Here we define different nodes to display normal block with phtml file, block by calling Knockout JS template as well as display UI_Component grid on front end.

Create codesample_index_index.xml file inside view/frontend/layout folder. 

<?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">
    <head>
        <title>Mage learn Code Sample</title>
        <css src="Magelearn_CodeSample::css/backend.css" />
    </head>
    <body>
        <referenceContainer name="content">
        	<block class="Magelearn\CodeSample\Block\Grid" name="codeSample_grid" template="Magelearn_CodeSample::grid/success.phtml">
            </block>
            <block class="Magelearn\CodeSample\Block\Index" name="magelearn_codesample_block" after="CodeSample_Grid" cacheable="false" template="Magelearn_CodeSample::index.phtml">
                <arguments>
                    <argument name="jsLayout" xsi:type="array">
                        <item name="components" xsi:type="array">
                            <item name="challenge" xsi:type="array">
                            	<item name="component" xsi:type="string">Magelearn_CodeSample/js/view/data</item>
                            </item>
                        </item>
                    </argument>
                </arguments>
            </block>
            <uiComponent name="magelearn_codesample_product_list_custom"/>
        </referenceContainer>
    </body>
</page>

We will add our css file _module.less inside view/frontend/web/css/source folder. 

Create success.phtml file inside view/frontend/templates/grid folder. This file display data from block file.

/** here you can get block class object by "$this" or "$block"  **/
/** here i'll use "$block" for get block object **/
<?php  $_gridrecords = $block->getCollection(); // get collection which we set in block class
?>
<?php if ($_gridrecords && count($_gridrecords)): ?>
    <div class="table-wrapper orders-history">
        <table class="data table table-order-items history" id="my-orders-table">
            <caption class="table-caption"><?php echo __('Grid Record') ?></caption>
            <thead>
                <tr>
                    <th scope="col" class="col id"><?php echo __('ID #') ?></th>
                    <th scope="col" class="col title"><?php echo __('Product SKU') ?></th>
                    <th scope="col" class="col date"><?php echo __('Additional Text') ?></th>
                </tr>
            </thead>
            <tbody>
                <?php  // read collection as magento1.x and display in list 
                       foreach ($_gridrecords as $_gridrecord): ?>
                    <tr>
                        <td class="col id"><?php echo $_gridrecord->getEntityId() ?></td>
                        <td class="col shipping">
                        	<?php if(null !== $_gridrecord->getProductIds() && $_gridrecord->getProductIds() !== '') {
                        		echo $block->getProductSkus($_gridrecord->getProductIds());
                        	}
                        	?>
                        </td>
                        <td class="col date"><?php echo $_gridrecord->getAdditionalText() ?></td>
                    </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
    </div>
    <?php if ($block->getPagerHtml()): ?>
        <div class="order-products-toolbar toolbar bottom"><?php echo $block->getPagerHtml(); // for display pager block which we create in block file.   ?></div>
    <?php endif ?>
<?php else: ?>
    <div class="message info empty"><span><?php echo __('grid records not available.'); ?></span></div>
<?php endif ?>
Create Block file Grid.php inside Block folder.
<?php
namespace Magelearn\CodeSample\Block;

class Grid extends \Magento\Framework\View\Element\Template
{
     protected $_gridFactory;
	 protected $_productFactory;
	 
     public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Magelearn\CodeSample\Model\CodesampleFactory $gridFactory,
        \Magento\Catalog\Model\ProductFactory $_productFactory,
        array $data = []
     ) {
        $this->_gridFactory = $gridFactory;
		$this->_productFactory = $_productFactory;
        parent::__construct($context, $data);
        //get collection of data 
        $collection = $this->_gridFactory->create()->getCollection();
        $this->setCollection($collection);
        $this->pageConfig->getTitle()->set(__('My Grid List'));
    }
 
    protected function _prepareLayout()
    {
        parent::_prepareLayout();
        if ($this->getCollection()) {
            // create pager block for collection 
            $pager = $this->getLayout()->createBlock(
                'Magento\Theme\Block\Html\Pager',
                'magelearn.grid.record.pager'
            )->setCollection(
                $this->getCollection() // assign collection to pager
            );
            $this->setChild('pager', $pager);// set pager block in layout
        }
        return $this;
    }
 
    /**
     * @return string
     */
    // method for get pager html
    public function getPagerHtml()
    {
        return $this->getChildHtml('pager');
    }
	
	public function getProductSkus($productids)
    {
    	$product_ids = $product_sku = [];
    	$product_ids = explode(",", $productids);
		
		foreach ($product_ids as $product_id) {
			$productdata = $this->_productFactory->create()->load($product_id);
			$product_sku[] = $productdata->getSku();
		}
		return trim(implode(",", $product_sku),",");
    }   
}
?>

Create index.phtml file inside view/frontend/templates folder. 

<?php $jsonProductData = $block->getProductCollectionJsonData(); ?>
<?php $notice = $block->getNotice() ?>
<div id="knockout-template" data-bind="scope:'challenge'">
    <!-- ko template: getTemplate() --><!-- /ko -->
    <script type="text/x-magento-init">
       {
           "#knockout-template": {
               "Magento_Ui/js/core/app": {
                   "components": {
                       "challenge": {
                            "component": "Magelearn_CodeSample/js/view/data",
                            "items": <?php echo $jsonProductData ?>,
                            "notice": <?php echo $notice ?>
                        }
                   }
               }
           }
       }
   </script>

   
</div>
To get data from block, we will create block file and return data into JSON format to display it on html template with knockout binding.
  
Create Block file Index.php inside Block folder.
<?php

namespace Magelearn\CodeSample\Block;

use Magento\Framework\View\Element\Template;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magelearn\CodeSample\Model\CodesampleFactory as DataFactory;
use Magento\Framework\Serialize\Serializer\Json as Serializer;

/**
 * Class Index
 *
 * @package Magelearn\CodeSample\Block
 */
class Index extends Template
{
    /**
     * @var array|\Magento\Checkout\Block\Checkout\LayoutProcessorInterface[]
     */
    protected $_layoutProcessors;

    /**
     * @var ScopeConfigInterface
     */
    protected $_scopeConfig;

    /**
     * @var DataFactory
     */
    protected $_dataFactory;

    /**
     * @var Serializer
     */
    protected $_serializer;
	
	protected $_productRepository;

    /**
     * Index constructor.
     *
     * @param ScopeConfigInterface $_scopeConfig
     * @param Template\Context     $context
     * @param DataFactory          $_dataFactory
     * @param Serializer           $_serializer
     * @param array                $_layoutProcessors
     * @param array                $data
     */
    public function __construct(
        ScopeConfigInterface $_scopeConfig,
        Template\Context $context,
        DataFactory $_dataFactory,
        Serializer $_serializer,
        \Magento\Catalog\Model\ProductRepository $productRepository,
        array $_layoutProcessors = [],
        array $data = []
    ) {
        parent::__construct($context, $data);
        $this->_scopeConfig = $_scopeConfig;
        $this->_dataFactory = $_dataFactory;
        $this->_serializer = $_serializer;
		$this->_productRepository = $productRepository;
        $this->jsLayout = isset($data['jsLayout'])
        && is_array(
            $data['jsLayout']
        ) ? $data['jsLayout'] : [];
        $this->_layoutProcessors = $_layoutProcessors;
    }


    /**
     * @return mixed
     */
    private function _getCollection()
    {
    	$codesampledata = $this->_dataFactory->create();
        $codesample_collection = $codesampledata->getCollection();
        return $codesample_collection;
    }

    /**
     * @return string
     */
    public function getJsLayout()
    {
        foreach ($this->_layoutProcessors as $processor) {
            $this->jsLayout = $processor->process($this->jsLayout);
        }
        return \Zend_Json::encode($this->jsLayout);
    }

    /**
     * @return mixed
     */
    public function getNotice()
    {
        return $this->_serializer->serialize($this->_scopeConfig->getValue(
            'codesample/general/notice_text'
        ));
    }

    /**
     * @return bool|false|string
     */
    public function getProductCollectionJsonData()
    {
        $_productCollection = $this->_getCollection();
        $i = 0;
        $productDataArray = array();
        foreach ($_productCollection as $product) {
        	$product_skus = '';
        	if(isset($product['product_ids']) && $product['product_ids'] != '') {
        		$product_ids = $product_sku = [];
        		$product_ids = explode(",", $product['product_ids']);
				
				foreach ($product_ids as $product_id) {
					$productdata = $this->_productRepository->getById($product_id);
					$product_sku[] = $productdata->getSku();
				}
				$product_skus = trim(implode(",", $product_sku),",");
        	}
            $productDataArray[$i] = array(
                'entity_id'       => $product['entity_id'],
                'product_ids'     => $product_skus,
                'additional_text' => $product['additional_text']
            );
            $i++;
        }
		
        return $this->_serializer->serialize($productDataArray);
    }
}
Now, as per that .phtml file, we will create our JS component file.
Create js file data.js inside
view/frontend/web/js/view folder.

define([
    'ko',
    'uiComponent',
], function (ko, Component) {
    'use strict';

    var self;
    return Component.extend({
        additionalText: ko.observable('Click a row, button, or list item to show additional text here.'),
        randomColour: ko.observable("rgb(0, 0, 0)"),
        defaults: {
            template: 'Magelearn_CodeSample/index',
        },
        initialize: function () {
            self = this;
            this._super();
            //call the subscribeToText function to run on intialize
            this.subscribeToText();
        },
        getAdditionalText: function (data,event) {
            self.additionalText(data.additional_text);
        },
        subscribeToText: function() {
            this.additionalText.subscribe(function(newValue) {
                console.log(newValue);
                self.updateTextColour();
            });
        },
        randomNumber: function() {
                return Math.floor((Math.random() * 255) + 1);
        },
        updateTextColour: function() {
            //define RGB values
            var red = self.randomNumber(),
                blue = self.randomNumber(),
                green = self.randomNumber();
                
            self.randomColour('rgb(' + red + ', ' + blue + ', ' + green + ')');
        }
    });
});

As per defined in the JS file, we will create our html template file with knockout binding syntax.
Create html file Index.html inside 
view/frontend/web/template folder.

<div class="notice">
    <p data-bind="text: notice"></p>
</div>
<h3>Table</h3>
<table class="data table text-table" id="codesample-data-table">
	<caption class="table-caption">Codesample Test Data</caption>
    <thead>
    <tr>
        <th scope="col" class="col entity_id">Entity ID</th>
        <th scope="col" class="col product_ids">Product SKU</th>
        <th scope="col" class="col button">Button</th>
    </tr>
    </thead>
    <tbody data-bind="foreach: items">
    <tr data-bind="click: $parent.getAdditionalText">
        <td data-th="Entity ID" class="col entity_id" data-bind="text: entity_id"></td>
        <td data-th="Product Ids" class="col product_sku" data-bind="text: product_ids"></td>
        <td data-th="Additional Text" class="col additional-text"><button data-bind="click: $parent.getAdditionalText">View Additional Text</button></td>
    </tr>
    </tbody>
</table>
<h3>Unordered List</h3>
<ul data-bind="foreach: items">
    <li class="unordered-text" data-bind="text: product_ids, click: $parent.getAdditionalText"></li>
</ul>
<h3>Paragraph</h3>
<div class="additional-text">
    <p data-bind="text: additionalText, style: {color: randomColour}"></p>
</div>
Create controller file Index.php inside Controller/Index
This file also have some additional method to display UI_Component admin grid on frontend, which you will learn later on this post.
<?php

namespace Magelearn\CodeSample\Controller\Index;

use Magento\Framework\View\Element\UiComponentInterface;
use Magento\Framework\Controller\ResultFactory;
/**
 * Class Index
 * @package Magelearn\CodeSample\Controller\Index
 */
class Index extends \Magelearn\CodeSample\Controller\CodeSampleAbstract
{
    /**
     * @var \Magento\Framework\View\Result\PageFactory
     */
    protected $resultPageFactory;
	protected $factory;
    /**
     * Constructor
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory,
        \Magento\Framework\View\Element\UiComponentFactory $factory
    ) {
        $this->resultPageFactory = $resultPageFactory;
		$this->factory = $factory;
        parent::__construct($context);
    }

    /**
     * Execute view action
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
    	$isAjax = $this->getRequest()->isAjax();	
    	if ($isAjax) {
    		$component = $this->factory->create($this->_request->getParam('namespace'));
            $this->prepareComponent($component);
            $this->_response->appendBody((string) $component->render());
		} else {
			return $this->resultPageFactory->create();	
		}
    }
	protected function prepareComponent(UiComponentInterface $component)
    {
        foreach ($component->getChildComponents() as $child) {
            $this->prepareComponent($child);
        }
        $component->prepare();
    }
}
Now, we will create CodeSampleAbstract.php file inside Magelearn/CodeSample/Controller
<?php

namespace Magelearn\CodeSample\Controller;

abstract class CodeSampleAbstract extends \Magento\Framework\App\Action\Action
{

}
To display our data on front end page we will start to create its necessary files for backend also.
We will start to create files as per defined in etc/di.xml nodes.

Create CodesampleRepositoryInterface.php file inside Api folder.
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Api;

use Magento\Framework\Api\SearchCriteriaInterface;

interface CodesampleRepositoryInterface
{

    /**
     * Save Codesample
     * @param \Magelearn\CodeSample\Api\Data\CodesampleInterface $codesample
     * @return \Magelearn\CodeSample\Api\Data\CodesampleInterface
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function save(
        \Magelearn\CodeSample\Api\Data\CodesampleInterface $codesample
    );

    /**
     * Retrieve Codesample
     * @param string $entiryId
     * @return \Magelearn\CodeSample\Api\Data\CodesampleInterface
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function get($entiryId);

    /**
     * Retrieve Codesample matching the specified criteria.
     * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria
     * @return \Magelearn\CodeSample\Api\Data\CodesampleSearchResultsInterface
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function getList(
        \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria
    );

    /**
     * Delete Codesample
     * @param \Magelearn\CodeSample\Api\Data\CodesampleInterface $codesample
     * @return bool true on success
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function delete(
        \Magelearn\CodeSample\Api\Data\CodesampleInterface $codesample
    );

    /**
     * Delete Codesample by ID
     * @param string $entiryId
     * @return bool true on success
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function deleteById($entiryId);
}
Create CodesampleInterface.php file inside Api/Data folder.
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Api\Data;

interface CodesampleInterface extends \Magento\Framework\Api\ExtensibleDataInterface
{

    const ENTITY_ID = 'entity_id';
    const PRODUCT_IDS = 'product_ids';
    const ADDITIONAL_TEXT = 'additional_text';

    /**
     * Get entity_id
     * @return string|null
     */
    public function getEntityId();

    /**
     * Set entity_id
     * @param string $entiryId
     * @return \Magelearn\CodeSample\Api\Data\CodesampleInterface
     */
    public function setEntityId($entiryId);
    /**
     * Retrieve existing extension attributes object or create a new one.
     * @return \Magelearn\CodeSample\Api\Data\CodesampleExtensionInterface|null
     */
    public function getExtensionAttributes();

    /**
     * Set an extension attributes object.
     * @param \Magelearn\CodeSample\Api\Data\CodesampleExtensionInterface $extensionAttributes
     * @return $this
     */
    public function setExtensionAttributes(
        \Magelearn\CodeSample\Api\Data\CodesampleExtensionInterface $extensionAttributes
    );

    /**
     * Get product_ids
     * @return string|null
     */
    public function getProductIds();

    /**
     * Set product_ids
     * @param string $productIds
     * @return \Magelearn\CodeSample\Api\Data\CodesampleInterface
     */
    public function setProductIds($productIds);

    /**
     * Get additional_text
     * @return string|null
     */
    public function getAdditionalText();

    /**
     * Set additional_text
     * @param string $additionalText
     * @return \Magelearn\CodeSample\Api\Data\CodesampleInterface
     */
    public function setAdditionalText($additionalText);
}

Create CodesampleSearchResultsInterface.php file inside Api/Data folder.
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Api\Data;

interface CodesampleSearchResultsInterface extends \Magento\Framework\Api\SearchResultsInterface
{

    /**
     * Get Codesample list.
     * @return \Magelearn\CodeSample\Api\Data\CodesampleInterface[]
     */
    public function getItems();

    /**
     * Set id list.
     * @param \Magelearn\CodeSample\Api\Data\CodesampleInterface[] $items
     * @return $this
     */
    public function setItems(array $items);
}
Create CodesampleRepository.php inside Model folder.
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Model;

use Magelearn\CodeSample\Api\CodesampleRepositoryInterface;
use Magelearn\CodeSample\Api\Data\CodesampleInterfaceFactory;
use Magelearn\CodeSample\Api\Data\CodesampleSearchResultsInterfaceFactory;
use Magelearn\CodeSample\Model\ResourceModel\Codesample as ResourceCodesample;
use Magelearn\CodeSample\Model\ResourceModel\Codesample\CollectionFactory as CodesampleCollectionFactory;
use Magento\Framework\Api\DataObjectHelper;
use Magento\Framework\Api\ExtensibleDataObjectConverter;
use Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface;
use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface;
use Magento\Framework\Exception\CouldNotDeleteException;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Reflection\DataObjectProcessor;
use Magento\Store\Model\StoreManagerInterface;

class CodesampleRepository implements CodesampleRepositoryInterface
{

    protected $codesampleCollectionFactory;

    protected $resource;

    protected $extensibleDataObjectConverter;
    protected $searchResultsFactory;

    protected $dataCodesampleFactory;

    private $storeManager;

    protected $dataObjectHelper;

    protected $codesampleFactory;

    protected $dataObjectProcessor;

    protected $extensionAttributesJoinProcessor;

    private $collectionProcessor;


    /**
     * @param ResourceCodesample $resource
     * @param CodesampleFactory $codesampleFactory
     * @param CodesampleInterfaceFactory $dataCodesampleFactory
     * @param CodesampleCollectionFactory $codesampleCollectionFactory
     * @param CodesampleSearchResultsInterfaceFactory $searchResultsFactory
     * @param DataObjectHelper $dataObjectHelper
     * @param DataObjectProcessor $dataObjectProcessor
     * @param StoreManagerInterface $storeManager
     * @param CollectionProcessorInterface $collectionProcessor
     * @param JoinProcessorInterface $extensionAttributesJoinProcessor
     * @param ExtensibleDataObjectConverter $extensibleDataObjectConverter
     */
    public function __construct(
        ResourceCodesample $resource,
        CodesampleFactory $codesampleFactory,
        CodesampleInterfaceFactory $dataCodesampleFactory,
        CodesampleCollectionFactory $codesampleCollectionFactory,
        CodesampleSearchResultsInterfaceFactory $searchResultsFactory,
        DataObjectHelper $dataObjectHelper,
        DataObjectProcessor $dataObjectProcessor,
        StoreManagerInterface $storeManager,
        CollectionProcessorInterface $collectionProcessor,
        JoinProcessorInterface $extensionAttributesJoinProcessor,
        ExtensibleDataObjectConverter $extensibleDataObjectConverter
    ) {
        $this->resource = $resource;
        $this->codesampleFactory = $codesampleFactory;
        $this->codesampleCollectionFactory = $codesampleCollectionFactory;
        $this->searchResultsFactory = $searchResultsFactory;
        $this->dataObjectHelper = $dataObjectHelper;
        $this->dataCodesampleFactory = $dataCodesampleFactory;
        $this->dataObjectProcessor = $dataObjectProcessor;
        $this->storeManager = $storeManager;
        $this->collectionProcessor = $collectionProcessor;
        $this->extensionAttributesJoinProcessor = $extensionAttributesJoinProcessor;
        $this->extensibleDataObjectConverter = $extensibleDataObjectConverter;
    }

    /**
     * {@inheritdoc}
     */
    public function save(
        \Magelearn\CodeSample\Api\Data\CodesampleInterface $codesample
    ) {
        /* if (empty($codesample->getStoreId())) {
            $storeId = $this->storeManager->getStore()->getId();
            $codesample->setStoreId($storeId);
        } */
        
        $codesampleData = $this->extensibleDataObjectConverter->toNestedArray(
            $codesample,
            [],
            \Magelearn\CodeSample\Api\Data\CodesampleInterface::class
        );
        
        $codesampleModel = $this->codesampleFactory->create()->setData($codesampleData);
        
        try {
            $this->resource->save($codesampleModel);
        } catch (\Exception $exception) {
            throw new CouldNotSaveException(__(
                'Could not save the codesample: %1',
                $exception->getMessage()
            ));
        }
        return $codesampleModel->getDataModel();
    }

    /**
     * {@inheritdoc}
     */
    public function get($codesampleId)
    {
        $codesample = $this->codesampleFactory->create();
        $this->resource->load($codesample, $codesampleId);
        if (!$codesample->getId()) {
            throw new NoSuchEntityException(__('Codesample with id "%1" does not exist.', $codesampleId));
        }
        return $codesample->getDataModel();
    }

    /**
     * {@inheritdoc}
     */
    public function getList(
        \Magento\Framework\Api\SearchCriteriaInterface $criteria
    ) {
        $collection = $this->codesampleCollectionFactory->create();
        
        $this->extensionAttributesJoinProcessor->process(
            $collection,
            \Magelearn\CodeSample\Api\Data\CodesampleInterface::class
        );
        
        $this->collectionProcessor->process($criteria, $collection);
        
        $searchResults = $this->searchResultsFactory->create();
        $searchResults->setSearchCriteria($criteria);
        
        $items = [];
        foreach ($collection as $model) {
            $items[] = $model->getDataModel();
        }
        
        $searchResults->setItems($items);
        $searchResults->setTotalCount($collection->getSize());
        return $searchResults;
    }

    /**
     * {@inheritdoc}
     */
    public function delete(
        \Magelearn\CodeSample\Api\Data\CodesampleInterface $codesample
    ) {
        try {
            $codesampleModel = $this->codesampleFactory->create();
            $this->resource->load($codesampleModel, $codesample->getCodesampleId());
            $this->resource->delete($codesampleModel);
        } catch (\Exception $exception) {
            throw new CouldNotDeleteException(__(
                'Could not delete the Codesample: %1',
                $exception->getMessage()
            ));
        }
        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function deleteById($entiryId)
    {
        return $this->delete($this->get($entiryId));
    }
}
Create Codesample.php inside Model/Data folder.
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Model\Data;

use Magelearn\CodeSample\Api\Data\CodesampleInterface;

class Codesample extends \Magento\Framework\Api\AbstractExtensibleObject implements CodesampleInterface
{

    /**
     * Get entity_id
     * @return string|null
     */
    public function getEntityId()
    {
        return $this->_get(self::ENTITY_ID);
    }

    /**
     * Set entity_id
     * @param string $entiryId
     * @return \Magelearn\CodeSample\Api\Data\CodesampleInterface
     */
    public function setEntityId($entiryId)
    {
        return $this->setData(self::ENTITY_ID, $entiryId);
    }

    /**
     * Retrieve existing extension attributes object or create a new one.
     * @return \Magelearn\CodeSample\Api\Data\CodesampleExtensionInterface|null
     */
    public function getExtensionAttributes()
    {
        return $this->_getExtensionAttributes();
    }

    /**
     * Set an extension attributes object.
     * @param \Magelearn\CodeSample\Api\Data\CodesampleExtensionInterface $extensionAttributes
     * @return $this
     */
    public function setExtensionAttributes(
        \Magelearn\CodeSample\Api\Data\CodesampleExtensionInterface $extensionAttributes
    ) {
        return $this->_setExtensionAttributes($extensionAttributes);
    }

    /**
     * Get product_ids
     * @return string|null
     */
    public function getProductIds()
    {
        return $this->_get(self::PRODUCT_IDS);
    }

    /**
     * Set product_ids
     * @param string $productIds
     * @return \Magelearn\CodeSample\Api\Data\CodesampleInterface
     */
    public function setProductIds($productIds)
    {
        return $this->setData(self::PRODUCT_IDS, $productIds);
    }

    /**
     * Get additional_text
     * @return string|null
     */
    public function getAdditionalText()
    {
        return $this->_get(self::ADDITIONAL_TEXT);
    }

    /**
     * Set additional_text
     * @param string $additionalText
     * @return \Magelearn\CodeSample\Api\Data\CodesampleInterface
     */
    public function setAdditionalText($additionalText)
    {
        return $this->setData(self::ADDITIONAL_TEXT, $additionalText);
    }
}
Create Codesample.php inside Model folder.
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Model;

use Magelearn\CodeSample\Api\Data\CodesampleInterface;
use Magelearn\CodeSample\Api\Data\CodesampleInterfaceFactory;
use Magento\Framework\Api\DataObjectHelper;

class Codesample extends \Magento\Framework\Model\AbstractModel
{

    protected $codesampleDataFactory;

    protected $_eventPrefix = 'magelearn_codesample';
    protected $dataObjectHelper;


    /**
     * @param \Magento\Framework\Model\Context $context
     * @param \Magento\Framework\Registry $registry
     * @param CodesampleInterfaceFactory $codesampleDataFactory
     * @param DataObjectHelper $dataObjectHelper
     * @param \Magelearn\CodeSample\Model\ResourceModel\Codesample $resource
     * @param \Magelearn\CodeSample\Model\ResourceModel\Codesample\Collection $resourceCollection
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\Model\Context $context,
        \Magento\Framework\Registry $registry,
        CodesampleInterfaceFactory $codesampleDataFactory,
        DataObjectHelper $dataObjectHelper,
        \Magelearn\CodeSample\Model\ResourceModel\Codesample $resource,
        \Magelearn\CodeSample\Model\ResourceModel\Codesample\Collection $resourceCollection,
        array $data = []
    ) {
        $this->codesampleDataFactory = $codesampleDataFactory;
        $this->dataObjectHelper = $dataObjectHelper;
        parent::__construct($context, $registry, $resource, $resourceCollection, $data);
    }

    /**
     * Retrieve codesample model with codesample data
     * @return CodesampleInterface
     */
    public function getDataModel()
    {
        $codesampleData = $this->getData();
        
        $codesampleDataObject = $this->codesampleDataFactory->create();
        $this->dataObjectHelper->populateWithArray(
            $codesampleDataObject,
            $codesampleData,
            CodesampleInterface::class
        );
        
        return $codesampleDataObject;
    }
}
Create Codesample.php inside Model/ResourceModel folder.
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Model\ResourceModel;

class Codesample extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
{

    /**
     * Define resource model
     *
     * @return void
     */
    protected function _construct()
    {
        $this->_init('magelearn_codesample', 'entity_id');
    }
}
Create Collection.php inside Model/ResourceModel/Codesample folder.
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Model\ResourceModel\Codesample;

class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
{

    /**
     * @var string
     */
    protected $_idFieldName = 'entity_id';
	protected $_previewFlag;

    /**
     * Define resource model
     *
     * @return void
     */
    protected function _construct()
    {
        $this->_init(
            \Magelearn\CodeSample\Model\Codesample::class,
            \Magelearn\CodeSample\Model\ResourceModel\Codesample::class
        );
		$this->_map['fields']['entity_id'] = 'main_table.entity_id';
    }
}
Now, to display this data into Magento Admin Grid, we will create below files:

Create menu.xml file inside etc/adminhtml folder.

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Backend:etc/menu.xsd">
	<menu>
		<add id="Magelearn::top_level" title="Magelearn" module="Magelearn_CodeSample" sortOrder="9999" resource="Magento_Backend::content"/>
		<add id="Magelearn_CodeSample::magelearn_codesample_managecode" title="Manage Codesample" module="Magelearn_CodeSample" sortOrder="9999" resource="Magento_Backend::content" parent="Magelearn::top_level" action="magelearn_codesample/codesample/index"/>
	</menu>
</config>

Create routes.xml file inside etc/adminhtml folder.

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
	<router id="admin">
		<route frontName="magelearn_codesample" id="magelearn_codesample">
			<module before="Magento_Backend" name="Magelearn_CodeSample"/>
		</route>
	</router>
</config>
To give system configuration option create system.xml file inside etc/adminhtml folder.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <tab id="magelearn" translate="label" sortOrder="10">
            <label>Code Sample</label>
        </tab>
        <section id="codesample" translate="label" sortOrder="130" showInDefault="1" showInWebsite="1" showInStore="1">
            <class>separator-top</class>
            <label>Code Challenge</label>
            <tab>magelearn</tab>
            <resource>Magelearn_CodeSample::additionaltext</resource>
            <group id="general" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0">
                <label>General Configuration</label>
                <field id="notice_text" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="0" showInStore="0">
                    <label>Notice Text</label>
                    <comment>This text will display on code challenge frontend page</comment>
                </field>
            </group>
        </section>
    </system>
</config>

Create acl.xml file inside etc folder.

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
	<acl>
		<resources>
			<resource id="Magento_Backend::admin">
				<resource id="Magelearn_CodeSample::Codesample" title="Codesample" sortOrder="10">
					<resource id="Magelearn_CodeSample::Codesample_save" title="Save Codesample" sortOrder="10"/>
					<resource id="Magelearn_CodeSample::Codesample_delete" title="Delete Codesample" sortOrder="20"/>
					<resource id="Magelearn_CodeSample::Codesample_update" title="Update Codesample" sortOrder="30"/>
					<resource id="Magelearn_CodeSample::Codesample_view" title="View Codesample" sortOrder="40"/>
				</resource>
			</resource>
		</resources>
	</acl>
</config>

Create magelearn_codesample_codesample_index.xml file inside view/adminhtml/layout folder.

<?xml version="1.0" ?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
	<update handle="styles"/>
	<body>
		<referenceContainer name="content">
			<uiComponent name="magelearn_codesample_codesample_listing"/>
		</referenceContainer>
	</body>
</page>

Create Index.php file inside Controller/Adminhtml/Codesample folder.

<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Controller\Adminhtml\Codesample;

class Index extends \Magento\Backend\App\Action
{

    protected $resultPageFactory;

    /**
     * Constructor
     *
     * @param \Magento\Backend\App\Action\Context $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     */
    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory
    ) {
        $this->resultPageFactory = $resultPageFactory;
        parent::__construct($context);
    }

    /**
     * Index action
     *
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $resultPage = $this->resultPageFactory->create();
            $resultPage->getConfig()->getTitle()->prepend(__("Codesample"));
            return $resultPage;
    }
}

Create magelearn_codesample_codesample_listing.xml file inside view/adminhtml/ui_component folder.

<?xml version="1.0" ?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
	<argument name="data" xsi:type="array">
		<item name="js_config" xsi:type="array">
			<item name="provider" xsi:type="string">magelearn_codesample_codesample_listing.magelearn_codesample_listing_data_source</item>
		</item>
	</argument>
	<settings>
		<spinner>magelearn_codesample_columns</spinner>
		<deps>
			<dep>magelearn_codesample_codesample_listing.magelearn_codesample_listing_data_source</dep>
		</deps>
		<buttons>
			<button name="add">
				<url path="*/*/new"/>
				<class>primary</class>
				<label translate="true">Add new Codesample</label>
			</button>
		</buttons>
	</settings>
	<dataSource name="magelearn_codesample_listing_data_source" component="Magento_Ui/js/grid/provider">
		<settings>
			<storageConfig>
				<param name="indexField" xsi:type="string">entity_id</param>
			</storageConfig>
			<updateUrl path="mui/index/render"/>
		</settings>
		<aclResource>Magelearn_CodeSample::Codesample</aclResource>
		<dataProvider name="magelearn_codesample_listing_data_source" class="Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider">
			<settings>
				<requestFieldName>id</requestFieldName>
				<primaryFieldName>entity_id</primaryFieldName>
			</settings>
		</dataProvider>
	</dataSource>
	<listingToolbar name="listing_top">
		<settings>
			<sticky>true</sticky>
		</settings>
		<bookmark name="bookmarks"/>
		<columnsControls name="columns_controls"/>
		<massaction name="listing_massaction">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="selectProvider" xsi:type="string">magelearn_codesample_codesample_listing.magelearn_codesample_codesample_listing.magelearn_codesample_columns.ids</item>
                    <item name="indexField" xsi:type="string">entity_id</item>
                </item>
            </argument>
            <action name="delete">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="type" xsi:type="string">delete</item>
                        <item name="label" xsi:type="string" translate="true">Delete</item>
                        <item name="url" xsi:type="url" path="magelearn_codesample/Codesample/massDelete"/>
                        <item name="confirm" xsi:type="array">
                            <item name="name" xsi:type="string" translate="true">Delete items</item>
                            <item name="message" xsi:type="string" translate="true">Are you sure you wan't to delete selected items?</item>
                        </item>
                    </item>
                </argument>
            </action>           
            <action name="edit">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="type" xsi:type="string">edit</item>
                        <item name="label" xsi:type="string" translate="true">Edit</item>
                        <item name="callback" xsi:type="array">
                            <item name="provider" xsi:type="string">magelearn_codesample_codesample_listing.magelearn_codesample_codesample_listing.magelearn_codesample_columns_editor</item>
                            <item name="target" xsi:type="string">editSelected</item>
                        </item>
                    </item>
                </argument>
            </action>
        </massaction>
		<filters name="listing_filters"/>
		<paging name="listing_paging"/>
		<filterSearch name="fulltext">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="provider" xsi:type="string">magelearn_codesample_codesample_listing.magelearn_codesample_listing_data_source</item>
                    <item name="chipsProvider" xsi:type="string">magelearn_codesample_codesample_listing.magelearn_codesample_codesample_listing.listing_top.listing_filters_chips</item>
                    <item name="storageConfig" xsi:type="array">
                        <item name="provider" xsi:type="string">magelearn_codesample_codesample_listing.magelearn_codesample_codesample_listing.listing_top.bookmarks</item>
                        <item name="namespace" xsi:type="string">current.search</item>
                    </item>
                </item>
            </argument>
        </filterSearch>
	</listingToolbar>
	<columns name="magelearn_codesample_columns">
		<settings>
			<editorConfig>
				<param name="selectProvider" xsi:type="string">magelearn_codesample_codesample_listing.magelearn_codesample_codesample_listing.magelearn_codesample_columns.ids</param>
				<param name="enabled" xsi:type="boolean">true</param>
				<param name="indexField" xsi:type="string">entity_id</param>
				<param name="clientConfig" xsi:type="array">
					<item name="saveUrl" xsi:type="url" path="magelearn_codesample/Codesample/inlineEdit"/>
					<item name="validateBeforeSave" xsi:type="boolean">false</item>
				</param>
			</editorConfig>
			<childDefaults>
				<param name="fieldAction" xsi:type="array">
					<item name="provider" xsi:type="string">magelearn_codesample_codesample_listing.magelearn_codesample_codesample_listing.magelearn_codesample_columns_editor</item>
					<item name="target" xsi:type="string">startEdit</item>
					<item name="params" xsi:type="array">
						<item name="0" xsi:type="string">${ $.$data.rowIndex }</item>
						<item name="1" xsi:type="boolean">true</item>
					</item>
				</param>
			</childDefaults>
		</settings>
		<selectionsColumn name="ids" sortOrder="50">
			<settings>
				<indexField>entity_id</indexField>
			</settings>
		</selectionsColumn>
		<column name="entity_id" sortOrder="60">
			<settings>
				<filter>text</filter>
				<sorting>asc</sorting>
				<label translate="true">ID</label>
			</settings>
		</column>
		<column name="product_ids" class="Magelearn\CodeSample\Ui\Component\Listing\Column\ProductSku" sortOrder="70">
                <settings>
	                <label translate="true">Product skus</label>
	                <dataType>text</dataType>
	                <filter>text</filter>
	                <bodyTmpl>ui/grid/cells/html</bodyTmpl>
	                <sortable>false</sortable>
	            </settings>
        </column>
		<column name="additional_text" sortOrder="80">
			<settings>
				<filter>text</filter>
				<label translate="true">Additional text</label>
				<editor>
					<editorType>text</editorType>
					<validation>
						<rule name="required-entry" xsi:type="boolean">false</rule>
					</validation>
				</editor>
			</settings>
		</column>
		<actionsColumn name="actions" class="Magelearn\CodeSample\Ui\Component\Listing\Column\CodesampleActions" sortOrder="90">
			<settings>
				<indexField>entity_id</indexField>
				<resizeEnabled>false</resizeEnabled>
				<resizeDefaultWidth>107</resizeDefaultWidth>
			</settings>
		</actionsColumn>
	</columns>
</listing>

As per defined In this listing.xml file, we will create our custom column renderer class file.
Ccreate ProductSku.php file inside Ui/Component/Listing/Column

<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Ui\Component\Listing\Column;

class ProductSku extends \Magento\Ui\Component\Listing\Columns\Column
{
	protected $_productRepository;

    /**
     * @param \Magento\Framework\View\Element\UiComponent\ContextInterface $context
     * @param \Magento\Framework\View\Element\UiComponentFactory $uiComponentFactory
     * @param \Magento\Framework\UrlInterface $urlBuilder
     * @param array $components
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\View\Element\UiComponent\ContextInterface $context,
        \Magento\Framework\View\Element\UiComponentFactory $uiComponentFactory,
        \Magento\Framework\UrlInterface $urlBuilder,
        \Magento\Catalog\Model\ProductRepository $productRepository,
        array $components = [],
        array $data = []
    ) {
        $this->urlBuilder = $urlBuilder;
		$this->_productRepository = $productRepository;
        parent::__construct($context, $uiComponentFactory, $components, $data);
    }

    /**
     * Prepare Data Source
     *
     * @param array $dataSource
     * @return array
     */
    public function prepareDataSource(array $dataSource)
    {
        if (isset($dataSource['data']['items'])) {
            foreach ($dataSource['data']['items'] as & $item) {
                if (isset($item['product_ids']) && $item['product_ids'] != '') {
                	$product_ids = $product_sku = [];
                    $product_ids = explode(",", $item['product_ids']);
					foreach ($product_ids as $product_id) {
						$productdata = $this->_productRepository->getById($product_id);
						$product_sku[] = $productdata->getSku();
					}
					$item['product_ids'] = trim(implode(",", $product_sku),",");
                }
            }
        }
        return $dataSource;
    }
}

Now, Create controller file NewAction.php file inside Controller/Adminhtml/Codesample folder.

<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Controller\Adminhtml\Codesample;

class NewAction extends \Magelearn\CodeSample\Controller\Adminhtml\Codesample
{

    protected $resultForwardFactory;

    /**
     * @param \Magento\Backend\App\Action\Context $context
     * @param \Magento\Framework\Registry $coreRegistry
     * @param \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory
     */
    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Framework\Registry $coreRegistry,
        \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory
    ) {
        $this->resultForwardFactory = $resultForwardFactory;
        parent::__construct($context, $coreRegistry);
    }

    /**
     * New action
     *
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        /** @var \Magento\Framework\Controller\Result\Forward $resultForward */
        $resultForward = $this->resultForwardFactory->create();
        return $resultForward->forward('edit');
    }
}

Create controller file Codesample.php file inside Controller/Adminhtml folder.

<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Controller\Adminhtml;

abstract class Codesample extends \Magento\Backend\App\Action
{

    const ADMIN_RESOURCE = 'Magelearn_CodeSample::top_level';
    protected $_coreRegistry;

    /**
     * @param \Magento\Backend\App\Action\Context $context
     * @param \Magento\Framework\Registry $coreRegistry
     */
    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Framework\Registry $coreRegistry
    ) {
        $this->_coreRegistry = $coreRegistry;
        parent::__construct($context);
    }

    /**
     * Init page
     *
     * @param \Magento\Backend\Model\View\Result\Page $resultPage
     * @return \Magento\Backend\Model\View\Result\Page
     */
    public function initPage($resultPage)
    {
        $resultPage->setActiveMenu(self::ADMIN_RESOURCE)
            ->addBreadcrumb(__('Magelearn'), __('Magelearn'))
            ->addBreadcrumb(__('Codesample'), __('Codesample'));
        return $resultPage;
    }
}

Create controller file Edit.php file inside Controller/Adminhtml/Codesample folder.

<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Controller\Adminhtml\Codesample;

class Edit extends \Magelearn\CodeSample\Controller\Adminhtml\Codesample
{

    protected $resultPageFactory;

    /**
     * @param \Magento\Backend\App\Action\Context $context
     * @param \Magento\Framework\Registry $coreRegistry
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     */
    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Framework\Registry $coreRegistry,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory
    ) {
        $this->resultPageFactory = $resultPageFactory;
        parent::__construct($context, $coreRegistry);
    }

    /**
     * Edit action
     *
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        // 1. Get ID and create model
        $id = $this->getRequest()->getParam('entity_id');
        $model = $this->_objectManager->create(\Magelearn\CodeSample\Model\Codesample::class);
        
        // 2. Initial checking
        if ($id) {
            $model->load($id);
            if (!$model->getId()) {
                $this->messageManager->addErrorMessage(__('This Codesample no longer exists.'));
                /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
                $resultRedirect = $this->resultRedirectFactory->create();
                return $resultRedirect->setPath('*/*/');
            }
        }
        $this->_coreRegistry->register('magelearn_codesample', $model);
        
        // 3. Build edit form
        /** @var \Magento\Backend\Model\View\Result\Page $resultPage */
        $resultPage = $this->resultPageFactory->create();
        $this->initPage($resultPage)->addBreadcrumb(
            $id ? __('Edit Codesample') : __('New Codesample'),
            $id ? __('Edit Codesample') : __('New Codesample')
        );
        $resultPage->getConfig()->getTitle()->prepend(__('Codesamples'));
        $resultPage->getConfig()->getTitle()->prepend($model->getId() ? __('Edit Codesample %1', $model->getId()) : __('New Codesample'));
        return $resultPage;
    }
}

Now, we will create layout file for new action.

Create layout file magelearn_codesample_codesample_new.xml file inside view/adminhtml/layout folder.

<?xml version="1.0" ?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
	<update handle="magelearn_codesample_codesample_edit"/>
</page>

Create layout file magelearn_codesample_codesample_edit.xml file inside view/adminhtml/layout folder.

<?xml version="1.0" ?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
	<update handle="styles"/>
	<body>
		<referenceContainer name="content">
			<uiComponent name="magelearn_codesample_codesample_form"/>
		</referenceContainer>
	</body>
</page>
Now, we will create our uiComponent  file for Add/edit form.

Create file magelearn_codesample_codesample_form.xml file inside view/adminhtml/ui_component folder.

<?xml version="1.0" ?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
	<argument name="data" xsi:type="array">
		<item name="js_config" xsi:type="array">
			<item name="provider" xsi:type="string">magelearn_codesample_codesample_form.codesample_form_data_source</item>
		</item>
		<item name="label" xsi:type="string" translate="true">General Information</item>
		<item name="template" xsi:type="string">templates/form/collapsible</item>
	</argument>
	<settings>
		<buttons>
			<button name="back" class="Magelearn\CodeSample\Block\Adminhtml\Codesample\Edit\BackButton"/>
			<button name="delete" class="Magelearn\CodeSample\Block\Adminhtml\Codesample\Edit\DeleteButton"/>
			<button name="save" class="Magelearn\CodeSample\Block\Adminhtml\Codesample\Edit\SaveButton"/>
			<button name="save_and_continue" class="Magelearn\CodeSample\Block\Adminhtml\Codesample\Edit\SaveAndContinueButton"/>
		</buttons>
		<namespace>magelearn_codesample_codesample_form</namespace>
		<dataScope>data</dataScope>
		<deps>
			<dep>magelearn_codesample_codesample_form.codesample_form_data_source</dep>
		</deps>
	</settings>
	<dataSource name="codesample_form_data_source">
		<argument name="data" xsi:type="array">
			<item name="js_config" xsi:type="array">
				<item name="component" xsi:type="string">Magento_Ui/js/form/provider</item>
			</item>
		</argument>
		<settings>
			<submitUrl path="*/*/save"/>
		</settings>
		<dataProvider name="codesample_form_data_source" class="Magelearn\CodeSample\Model\Codesample\DataProvider">
			<settings>
				<requestFieldName>entity_id</requestFieldName>
				<primaryFieldName>entity_id</primaryFieldName>
			</settings>
		</dataProvider>
	</dataSource>
	<fieldset name="general">
		<settings>
			<label>General</label>
		</settings>
		<field name="product_ids" component="Magelearn_CodeSample/js/components/select-product" formElement="select" sortOrder="20">
			<argument name="data" xsi:type="array">
				<item name="config" xsi:type="array">
					<item name="filterOptions" xsi:type="boolean">true</item><!--to add filter in select-ui-->
		            <item name="multiple" xsi:type="boolean">true</item><!--select multiple or not-->
		            <item name="showCheckbox" xsi:type="boolean">true</item>
		            <!-- checkbox will not display if multiple == false -->
		            <item name="disableLabel" xsi:type="boolean">true</item>
				</item>
			</argument>
			<settings>
				<required>true</required>
				<validation>
					<rule name="required-entry" xsi:type="boolean">true</rule>
				</validation>
				<elementTmpl>ui/grid/filters/elements/ui-select</elementTmpl>
				<label translate="true">Select Product</label>
				<dataScope>product_ids</dataScope>
				<componentType>field</componentType>
		        <listens>
		            <link name="${ $.namespace }.${ $.namespace }:responseData">setParsed</link>
		        </listens>
			</settings>
			<formElements>
		        <select>
		            <settings>
		                <options class="Magelearn\CodeSample\Ui\Component\Create\Form\Product\Options"/>
		            </settings>
		        </select>
		    </formElements>
		</field>
		<field name="additional_text" formElement="textarea" sortOrder="30">
			<argument name="data" xsi:type="array">
				<item name="config" xsi:type="array">
					<item name="source" xsi:type="string">Codesample</item>
				</item>
			</argument>
			<settings>
				<dataType>text</dataType>
				<label translate="true">Additional text</label>
				<dataScope>additional_text</dataScope>
				<validation>
					<rule name="required-entry" xsi:type="boolean">false</rule>
				</validation>
			</settings>
		</field>
	</fieldset>
</form>

As per code highlighted in above form, To display the selection of the product SKU, we will going to create below files.

Create select-product.js file inside view/adminhtml/web/js/components folder.

define([
    'Magento_Ui/js/form/element/ui-select'
], function (Select) {
    'use strict';
    return Select.extend({
        /**
         * Parse data and set it to options.
         *
         * @param {Object} data - Response data object.
         * @returns {Object}
         */
        setParsed: function (data) {
            var option = this.parseData(data);
            if (data.error) {
                return this;
            }
            this.options([]);
            this.setOption(option);
            this.set('newOption', option);
        },
        /**
         * Normalize option object.
         *
         * @param {Object} data - Option object.
         * @returns {Object}
         */
        parseData: function (data) {
            console.log(data);
            return {
                value: data.product.entity_id,
                label: data.product.sku
            };
        }
    });
});

Here, Product options will be fetched from options class as per defined in magelearn_codesample_codesample_form.xml file.

Now Create Options.php file inside Magelearn/CodeSample/Ui/Component/Create/Form/Product folder.

<?php
namespace Magelearn\CodeSample\Ui\Component\Create\Form\Product;

use Magento\Framework\Data\OptionSourceInterface;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory;
use Magento\Framework\App\RequestInterface;

/**
 * Class Options
 *
 * @package Magelearn\CodeSample\Ui\Component\Create\Form\Product
 */
class Options implements OptionSourceInterface
{

    /**
     * @var ProductCollectionFactory
     */
    protected $productCollectionFactory;

    /**
     * @var RequestInterface
     */
    protected $request;

    /**
     * @var array
     */
    protected $productsArray;

    /**
     * @param ProductCollectionFactory $productCollectionFactory
     * @param RequestInterface $request
     */
    public function __construct(

        ProductCollectionFactory $productCollectionFactory,
        RequestInterface $request
    ) {
        $this->productCollectionFactory = $productCollectionFactory;
        $this->request = $request;
    }

    /**
     * @return array|null
     */
    public function toOptionArray()
    {
        return $this->getProductArray();
    }

    /**
     * @return array|null
     */
    protected function getProductArray() {
        if ($this->productsArray === null) {
            $productCollection = $this->productCollectionFactory->create();
			$productCollection->addAttributeToSelect('*');
			//$productCollection->setPageSize(10);
			/* setPageSize if you are facing problem when loading admin grid page */

            foreach($productCollection as $product) {
            	$productId = $product->getEntityId();
                if (!isset($productById[$productId])) {
                    $productById[$productId] = [
                        'value' => $productId
                    ];
                }
                $productById[$productId]['label'] = $product->getSku();
				
            }

			$this->productsArray = $productById;
        }
			return $this->productsArray;
    }
}

Now, We will create our dataprovider file to provide data values to this xml edit form.

Create DataProvider.php file inside Model/CodeSample folder.

<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Model\Codesample;

use Magelearn\CodeSample\Model\ResourceModel\Codesample\CollectionFactory;
use Magento\Framework\App\Request\DataPersistorInterface;

class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
{

    protected $loadedData;
    protected $dataPersistor;

    protected $collection;


    /**
     * Constructor
     *
     * @param string $name
     * @param string $primaryFieldName
     * @param string $requestFieldName
     * @param CollectionFactory $collectionFactory
     * @param DataPersistorInterface $dataPersistor
     * @param array $meta
     * @param array $data
     */
    public function __construct(
        $name,
        $primaryFieldName,
        $requestFieldName,
        CollectionFactory $collectionFactory,
        DataPersistorInterface $dataPersistor,
        array $meta = [],
        array $data = []
    ) {
        $this->collection = $collectionFactory->create();
        $this->dataPersistor = $dataPersistor;
        parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data);
    }

    /**
     * Get data
     *
     * @return array
     */
    public function getData()
    {
        if (isset($this->loadedData)) {
            return $this->loadedData;
        }
        $items = $this->collection->getItems();
        foreach ($items as $model) {
            $this->loadedData[$model->getId()] = $model->getData();
			$this->loadedData[$model->getId()]['product_ids'] = explode(",", $model->getData('product_ids'));
        }
		
        $data = $this->dataPersistor->get('magelearn_codesample');
        
        if (!empty($data)) {
            $model = $this->collection->getNewEmptyItem();
            $model->setData($data);
            $this->loadedData[$model->getId()] = $model->getData();
            $this->dataPersistor->clear('magelearn_codesample');
        }
        
        return $this->loadedData;
    }
}

To save this form data, we will create controller file Save.php file inside Controller/Adminhtml/Codesample folder.

<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Controller\Adminhtml\Codesample;

use Magento\Framework\Exception\LocalizedException;

class Save extends \Magento\Backend\App\Action
{

    protected $dataPersistor;

    /**
     * @param \Magento\Backend\App\Action\Context $context
     * @param \Magento\Framework\App\Request\DataPersistorInterface $dataPersistor
     */
    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Framework\App\Request\DataPersistorInterface $dataPersistor
    ) {
        $this->dataPersistor = $dataPersistor;
        parent::__construct($context);
    }

    /**
     * Save action
     *
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
        $resultRedirect = $this->resultRedirectFactory->create();
        $data = $this->getRequest()->getPostValue();
        if ($data) {
            $id = $this->getRequest()->getParam('entity_id');
        
            $model = $this->_objectManager->create(\Magelearn\CodeSample\Model\Codesample::class)->load($id);
            if (!$model->getId() && $id) {
                $this->messageManager->addErrorMessage(__('This Codesample no longer exists.'));
                return $resultRedirect->setPath('*/*/');
            }
        	if(is_array($data['product_ids']) && !empty($data['product_ids'])) {
        		$data['product_ids'] = trim(implode(",", $data['product_ids']), ",");
        	}
            $model->setData($data);
        
            try {
                $model->save();
                $this->messageManager->addSuccessMessage(__('You saved the Codesample.'));
                $this->dataPersistor->clear('magelearn_codesample_codesample');
        
                if ($this->getRequest()->getParam('back')) {
                    return $resultRedirect->setPath('*/*/edit', ['codesample_id' => $model->getId()]);
                }
                return $resultRedirect->setPath('*/*/');
            } catch (LocalizedException $e) {
                $this->messageManager->addErrorMessage($e->getMessage());
            } catch (\Exception $e) {
                $this->messageManager->addExceptionMessage($e, __('Something went wrong while saving the Codesample.'));
            }
        
            $this->dataPersistor->set('magelearn_codesample_codesample', $data);
            return $resultRedirect->setPath('*/*/edit', ['codesample_id' => $this->getRequest()->getParam('codesample_id')]);
        }
        return $resultRedirect->setPath('*/*/');
    }
}
Now we will create different action button files (Edit, Delete, Reset, Save, Save and Continue) defined in add/edit form.

Create file 
BackButton.php inside Block/Adminhtml/Codesample/Edit folder.
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Block\Adminhtml\Codesample\Edit;

use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface;

class BackButton extends GenericButton implements ButtonProviderInterface
{

    /**
     * @return array
     */
    public function getButtonData()
    {
        return [
            'label' => __('Back'),
            'on_click' => sprintf("location.href = '%s';", $this->getBackUrl()),
            'class' => 'back',
            'sort_order' => 10
        ];
    }

    /**
     * Get URL for back (reset) button
     *
     * @return string
     */
    public function getBackUrl()
    {
        return $this->getUrl('*/*/');
    }
}
Create GenericButton.php file inside Block/Adminhtml/Codesample/Edit folder.
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Block\Adminhtml\Codesample\Edit;

use Magento\Backend\Block\Widget\Context;

abstract class GenericButton
{

    protected $context;

    /**
     * @param \Magento\Backend\Block\Widget\Context $context
     */
    public function __construct(Context $context)
    {
        $this->context = $context;
    }

    /**
     * Return model ID
     *
     * @return int|null
     */
    public function getModelId()
    {
        return $this->context->getRequest()->getParam('codesample_id');
    }

    /**
     * Generate url by route and parameters
     *
     * @param   string $route
     * @param   array $params
     * @return  string
     */
    public function getUrl($route = '', $params = [])
    {
        return $this->context->getUrlBuilder()->getUrl($route, $params);
    }
}
Create DeleteButton.php file inside Block/Adminhtml/Codesample/Edit folder.
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Block\Adminhtml\Codesample\Edit;

use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface;

class DeleteButton extends GenericButton implements ButtonProviderInterface
{

    /**
     * @return array
     */
    public function getButtonData()
    {
        $data = [];
        if ($this->getModelId()) {
            $data = [
                'label' => __('Delete Codesample'),
                'class' => 'delete',
                'on_click' => 'deleteConfirm(\'' . __(
                    'Are you sure you want to do this?'
                ) . '\', \'' . $this->getDeleteUrl() . '\')',
                'sort_order' => 20,
            ];
        }
        return $data;
    }

    /**
     * Get URL for delete button
     *
     * @return string
     */
    public function getDeleteUrl()
    {
        return $this->getUrl('*/*/delete', ['codesample_id' => $this->getModelId()]);
    }
}
Create SaveButton.php file inside Block/Adminhtml/Codesample/Edit folder.
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Block\Adminhtml\Codesample\Edit;

use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface;

class SaveButton extends GenericButton implements ButtonProviderInterface
{

    /**
     * @return array
     */
    public function getButtonData()
    {
        return [
            'label' => __('Save Codesample'),
            'class' => 'save primary',
            'data_attribute' => [
                'mage-init' => ['button' => ['event' => 'save']],
                'form-role' => 'save',
            ],
            'sort_order' => 90,
        ];
    }
}
Create SaveAndContinueButton.php file inside Block/Adminhtml/Codesample/Edit folder.
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Block\Adminhtml\Codesample\Edit;

use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface;

class SaveAndContinueButton extends GenericButton implements ButtonProviderInterface
{

    /**
     * @return array
     */
    public function getButtonData()
    {
        return [
            'label' => __('Save and Continue Edit'),
            'class' => 'save',
            'data_attribute' => [
                'mage-init' => [
                    'button' => ['event' => 'saveAndContinueEdit'],
                ],
            ],
            'sort_order' => 80,
        ];
    }
}
Now, we will define our actionColumn files.

Create CodesampleActions.php file inside Ui\Component\Listing\Column folder.
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Ui\Component\Listing\Column;

class CodesampleActions extends \Magento\Ui\Component\Listing\Columns\Column
{

    const URL_PATH_DELETE = 'magelearn_codesample/codesample/delete';
    const URL_PATH_DETAILS = 'magelearn_codesample/codesample/details';
    protected $urlBuilder;
    const URL_PATH_EDIT = 'magelearn_codesample/codesample/edit';

    /**
     * @param \Magento\Framework\View\Element\UiComponent\ContextInterface $context
     * @param \Magento\Framework\View\Element\UiComponentFactory $uiComponentFactory
     * @param \Magento\Framework\UrlInterface $urlBuilder
     * @param array $components
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\View\Element\UiComponent\ContextInterface $context,
        \Magento\Framework\View\Element\UiComponentFactory $uiComponentFactory,
        \Magento\Framework\UrlInterface $urlBuilder,
        array $components = [],
        array $data = []
    ) {
        $this->urlBuilder = $urlBuilder;
        parent::__construct($context, $uiComponentFactory, $components, $data);
    }

    /**
     * Prepare Data Source
     *
     * @param array $dataSource
     * @return array
     */
    public function prepareDataSource(array $dataSource)
    {
        if (isset($dataSource['data']['items'])) {
            foreach ($dataSource['data']['items'] as & $item) {
                if (isset($item['entity_id'])) {
                    $item[$this->getData('name')] = [
                        'edit' => [
                            'href' => $this->urlBuilder->getUrl(
                                static::URL_PATH_EDIT,
                                [
                                    'entity_id' => $item['entity_id']
                                ]
                            ),
                            'label' => __('Edit')
                        ],
                        'delete' => [
                            'href' => $this->urlBuilder->getUrl(
                                static::URL_PATH_DELETE,
                                [
                                    'entity_id' => $item['entity_id']
                                ]
                            ),
                            'label' => __('Delete'),
                            'confirm' => [
                                'title' => __('Delete "${ $.$data.title }"'),
                                'message' => __('Are you sure you wan\'t to delete a "${ $.$data.title }" record?')
                            ]
                        ]
                    ];
                }
            }
        }
        
        return $dataSource;
    }
}
Now, we will create remaining action controller files.

Create Delete.php file inside Controller/Adminhtml/Codesample
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Controller\Adminhtml\Codesample;

class Delete extends \Magelearn\CodeSample\Controller\Adminhtml\Codesample
{

    /**
     * Delete action
     *
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
        $resultRedirect = $this->resultRedirectFactory->create();
        // check if we know what should be deleted
        $id = $this->getRequest()->getParam('entity_id');
        if ($id) {
            try {
                // init model and delete
                $model = $this->_objectManager->create(\Magelearn\CodeSample\Model\Codesample::class);
                $model->load($id);
                $model->delete();
                // display success message
                $this->messageManager->addSuccessMessage(__('You deleted the Codesample.'));
                // go to grid
                return $resultRedirect->setPath('*/*/');
            } catch (\Exception $e) {
                // display error message
                $this->messageManager->addErrorMessage($e->getMessage());
                // go back to edit form
                return $resultRedirect->setPath('*/*/edit', ['entity_id' => $id]);
            }
        }
        // display error message
        $this->messageManager->addErrorMessage(__('We can\'t find a Codesample to delete.'));
        // go to grid
        return $resultRedirect->setPath('*/*/');
    }
}
Create InlineEdit.php file inside Controller/Adminhtml/Codesample folder.
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magelearn\CodeSample\Controller\Adminhtml\Codesample;

class InlineEdit extends \Magento\Backend\App\Action
{

    protected $jsonFactory;

    /**
     * @param \Magento\Backend\App\Action\Context $context
     * @param \Magento\Framework\Controller\Result\JsonFactory $jsonFactory
     */
    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Framework\Controller\Result\JsonFactory $jsonFactory
    ) {
        parent::__construct($context);
        $this->jsonFactory = $jsonFactory;
    }

    /**
     * Inline edit action
     *
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        /** @var \Magento\Framework\Controller\Result\Json $resultJson */
        $resultJson = $this->jsonFactory->create();
        $error = false;
        $messages = [];
        
        if ($this->getRequest()->getParam('isAjax')) {
            $postItems = $this->getRequest()->getParam('items', []);
            if (!count($postItems)) {
                $messages[] = __('Please correct the data sent.');
                $error = true;
            } else {
                foreach (array_keys($postItems) as $modelid) {
                    /** @var \Magelearn\CodeSample\Model\Codesample $model */
                    $model = $this->_objectManager->create(\Magelearn\CodeSample\Model\Codesample::class)->load($modelid);
                    try {
                        $model->setData(array_merge($model->getData(), $postItems[$modelid]));
                        $model->save();
                    } catch (\Exception $e) {
                        $messages[] = "[Codesample ID: {$modelid}]  {$e->getMessage()}";
                        $error = true;
                    }
                }
            }
        }
        
        return $resultJson->setData([
            'messages' => $messages,
            'error' => $error
        ]);
    }
}
Create MassDelete.php file inside Controller/Adminhtml/Codesample folder.
<?php
declare(strict_types=1);

namespace Magelearn\CodeSample\Controller\Adminhtml\Codesample;

use Magento\Framework\Controller\ResultFactory;
use Magento\Backend\App\Action\Context;
use Magento\Ui\Component\MassAction\Filter;
use Magelearn\CodeSample\Model\ResourceModel\Codesample\CollectionFactory;

/**
 * Class MassDelete
 * @package Magelearn\CodeSample\Controller\Adminhtml\Codesample
 */
 
class MassDelete extends \Magento\Backend\App\Action
{
	/**
     * @var Filter
     */
    protected $filter;
    /**
     * @var CollectionFactory
     */
    protected $collectionFactory;

    /**
     * @param Context $context
     * @param Filter $filter
     * @param CollectionFactory $collectionFactory
     */
    public function __construct(Context $context, Filter $filter, CollectionFactory $collectionFactory)
    {
        $this->filter = $filter;
        $this->collectionFactory = $collectionFactory;
        parent::__construct($context);
    }
    /**
     * Execute action
     *
     * @return \Magento\Backend\Model\View\Result\Redirect
     * @throws \Magento\Framework\Exception\LocalizedException|\Exception
     */
    public function execute()
    {
        $collection = $this->filter->getCollection($this->collectionFactory->create());
        $collectionSize = $collection->getSize();

        foreach ($collection as $page) {
            $page->delete();
        }
        $this->messageManager->addSuccess(__('A total of %1 record(s) have been deleted.', $collectionSize));
        /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
        $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
        return $resultRedirect->setPath('*/*/');
    }
}
Now to display admin grid on front end, we will first create front end di.xml file.
Create di.xml file inside etc/frontend folder.
<?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="Magelearn\CodeSample\Api\CodesampleRepositoryInterface" type="Magelearn\CodeSample\Model\CodesampleRepository"/>
	<preference for="Magelearn\CodeSample\Api\Data\CodesampleInterface" type="Magelearn\CodeSample\Model\Data\Codesample"/>
	<preference for="Magelearn\CodeSample\Api\Data\CodesampleSearchResultsInterface" type="Magento\Framework\Api\SearchResults"/>
   <virtualType name="Magelearn\CodeSample\Model\ResourceModel\Codesample\Grid\Collection" type="Magelearn\CodeSample\Ui\DataProvider\SearchResult">
        <arguments>
            <argument name="mainTable" xsi:type="string">magelearn_codesample</argument>
            <argument name="resourceModel" xsi:type="string">Magelearn\CodeSample\Model\ResourceModel\Codesample\Collection</argument>
        </arguments>
    </virtualType>
    <type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
        <arguments>
            <argument name="collections" xsi:type="array">
                <item name="magelearn_codesample_product_list_custom_data_source" xsi:type="string">Magelearn\CodeSample\Model\ResourceModel\Codesample\Grid\Collection</item>
            </argument>
        </arguments>
    </type>
    <type name="Magento\Framework\View\Element\UiComponent\Argument\Interpreter\ConfigurableObject">
        <arguments>
            <argument name="classWhitelist" xsi:type="array">
                <item name="0" xsi:type="string">Magento\Framework\Data\OptionSourceInterface</item>
                <item name="1" xsi:type="string">Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface</item>
                <item name="2" xsi:type="string">Magento\Framework\View\Element\UiComponent\ContextInterface</item>
            </argument>
        </arguments>
    </type>
</config>

As you can see we have defined our Admin grid UI_Component in frontend layout file view/frontend/layout/codesample_index_index.xml

So, we will create magelearn_codesample_product_list_custom.xml file inside view/frontend/ui_component folder.
<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
	<argument name="context" xsi:type="configurableObject">
        <argument name="class" xsi:type="string">Magento\Framework\View\Element\UiComponent\Context</argument>
        <argument name="namespace" xsi:type="string">magelearn_codesample_product_list_custom</argument>
    </argument>
    <argument name="data" xsi:type="array">
        <item name="js_config" xsi:type="array">
            <item name="provider" xsi:type="string">magelearn_codesample_product_list_custom.magelearn_codesample_product_list_custom_data_source</item>
            <item name="deps" xsi:type="string">magelearn_codesample_product_list_custom.magelearn_codesample_product_list_custom_data_source</item>
        </item>
        <item name="spinner" xsi:type="string">products_columns</item>
    </argument>
    <dataSource name="magelearn_codesample_product_list_custom_data_source">
        <argument name="dataProvider" xsi:type="configurableObject">
            <argument name="class" xsi:type="string">Magelearn\CodeSample\Ui\DataProvider\DataProvider</argument>
            <argument name="name" xsi:type="string">magelearn_codesample_product_list_custom_data_source</argument>
            <argument name="primaryFieldName" xsi:type="string">entity_id</argument>
            <argument name="requestFieldName" xsi:type="string">id</argument>
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/provider</item>
                    <item name="update_url" xsi:type="url" path="codesample/index/index"/>
                    <item name="storageConfig" xsi:type="array">
                        <item name="indexField" xsi:type="string">entity_id</item>
                    </item>
                </item>
            </argument>
        </argument>
    </dataSource>
    <filters name="listing_filters">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="columnsProvider" xsi:type="string">magelearn_codesample_product_list_custom.magelearn_codesample_product_list_custom.products_columns</item>
                <item name="storageConfig" xsi:type="array">
                    <item name="provider" xsi:type="string">magelearn_codesample_product_list_custom.magelearn_codesample_product_list_custom.listing_top.bookmarks</item>
                    <item name="namespace" xsi:type="string">current.filters</item>
                </item>
                <item name="childDefaults" xsi:type="array">
                    <item name="provider" xsi:type="string">magelearn_codesample_product_list_custom.magelearn_codesample_product_list_custom.listing_top.listing_filters</item>
                    <item name="imports" xsi:type="array">
                        <item name="visible" xsi:type="string">magelearn_codesample_product_list_custom.magelearn_codesample_product_list_custom.products_columns.${ $.index }:visible</item>
                    </item>
                </item>
            </item>
        </argument>
    </filters>
    <columns name="products_columns">
        <selectionsColumn name="ids">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="indexField" xsi:type="string">entity_id</item>
                </item>
            </argument>
        </selectionsColumn>
        <column name="entity_id" sortOrder="60">
			<settings>
				<filter>text</filter>
				<sorting>asc</sorting>
				<label translate="true">ID</label>
			</settings>
		</column>
		<column name="product_ids" class="Magelearn\CodeSample\Ui\Component\Listing\Column\ProductSku" sortOrder="70">
                <settings>
	                <label translate="true">Product skus</label>
	                <dataType>text</dataType>
	                <filter>text</filter>
	                <bodyTmpl>ui/grid/cells/html</bodyTmpl>
	                <sortable>false</sortable>
	            </settings>
        </column>
		<column name="additional_text" sortOrder="80">
			<settings>
				<filter>text</filter>
				<label translate="true">Additional text</label>
				<editor>
					<editorType>text</editorType>
					<validation>
						<rule name="required-entry" xsi:type="boolean">false</rule>
					</validation>
				</editor>
			</settings>
		</column>
    </columns>
    <paging name="listing_paging">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="storageConfig" xsi:type="array">
                    <item name="provider" xsi:type="string">magelearn_codesample_product_list_custom.magelearn_codesample_product_list_custom.listing_top.bookmarks</item>
                    <item name="namespace" xsi:type="string">current.paging</item>
                </item>
                <item name="selectProvider" xsi:type="string">magelearn_codesample_product_list_custom.magelearn_codesample_product_list_custom.products_columns.ids</item>
            </item>
        </argument>
    </paging>
</listing>
In Above ui_component xml file, we have defined our own dataprovider class.
So, we will going to create 
DataProvider.php file inside Ui/DataProvider folder.
<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Magelearn\CodeSample\Ui\DataProvider;

use Magento\Framework\Api\FilterBuilder;
use Magento\Framework\Api\Search\ReportingInterface;
use Magento\Framework\Api\Search\SearchCriteria;
use Magento\Framework\Api\Search\SearchCriteriaBuilder;
use Magento\Framework\Api\Search\SearchResultInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface;

use Magento\Framework\App\Http\Context;

/**
 * Class DataProvider
 */
class DataProvider implements DataProviderInterface
{
    /**
     * Data Provider name
     *
     * @var string
     */
    protected $name;

    /**
     * Data Provider Primary Identifier name
     *
     * @var string
     */
    protected $primaryFieldName;

    /**
     * Data Provider Request Parameter Identifier name
     *
     * @var string
     */
    protected $requestFieldName;

    /**
     * @var array
     */
    protected $meta = [];

    /**
     * Provider configuration data
     *
     * @var array
     */
    protected $data = [];

    /**
     * @var ReportingInterface
     */
    protected $reporting;

    /**
     * @var FilterBuilder
     */
    protected $filterBuilder;

    /**
     * @var SearchCriteriaBuilder
     */
    protected $searchCriteriaBuilder;

    /**
     * @var RequestInterface
     */
    protected $request;

    /**
     * @var SearchCriteria
     */
    protected $searchCriteria;

    protected $_httpContext;

    /**
     * @param string $name
     * @param string $primaryFieldName
     * @param string $requestFieldName
     * @param ReportingInterface $reporting
     * @param SearchCriteriaBuilder $searchCriteriaBuilder
     * @param RequestInterface $request
     * @param FilterBuilder $filterBuilder
     * @param array $meta
     * @param array $data
     */
    public function __construct(
        $name,
        $primaryFieldName,
        $requestFieldName,
        ReportingInterface $reporting,
        SearchCriteriaBuilder $searchCriteriaBuilder,
        RequestInterface $request,
        FilterBuilder $filterBuilder,
        Context $httpContext,
        array $meta = [],
        array $data = []
    ) {
        $this->request = $request;
        $this->filterBuilder = $filterBuilder;
        $this->name = $name;
        $this->primaryFieldName = $primaryFieldName;
        $this->requestFieldName = $requestFieldName;
        $this->reporting = $reporting;
        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
        $this->_httpContext = $httpContext;
        $this->meta = $meta;
        $this->data = $data;
        $this->prepareUpdateUrl();
    }

    /**
     * @return void
     */
    protected function prepareUpdateUrl()
    {
        if (!isset($this->data['config']['filter_url_params'])) {
            return;
        }
        foreach ($this->data['config']['filter_url_params'] as $paramName => $paramValue) {
            if ('*' == $paramValue) {
                $paramValue = $this->request->getParam($paramName);
            }
            if ($paramValue) {
                $this->data['config']['update_url'] = sprintf(
                    '%s%s/%s/',
                    $this->data['config']['update_url'],
                    $paramName,
                    $paramValue
                );
                $this->addFilter(
                    $this->filterBuilder->setField($paramName)->setValue($paramValue)->setConditionType('eq')->create()
                );
            }
        }
    }

    /**
     * Get Data Provider name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Get primary field name
     *
     * @return string
     */
    public function getPrimaryFieldName()
    {
        return $this->primaryFieldName;
    }

    /**
     * Get field name in request
     *
     * @return string
     */
    public function getRequestFieldName()
    {
        return $this->requestFieldName;
    }

    /**
     * @return array
     */
    public function getMeta()
    {
        return $this->meta;
    }

    /**
     * Get field Set meta info
     *
     * @param string $fieldSetName
     * @return array
     */
    public function getFieldSetMetaInfo($fieldSetName)
    {
        return isset($this->meta[$fieldSetName]) ? $this->meta[$fieldSetName] : [];
    }

    /**
     * @param string $fieldSetName
     * @return array
     */
    public function getFieldsMetaInfo($fieldSetName)
    {
        return isset($this->meta[$fieldSetName]['children']) ? $this->meta[$fieldSetName]['children'] : [];
    }

    /**
     * @param string $fieldSetName
     * @param string $fieldName
     * @return array
     */
    public function getFieldMetaInfo($fieldSetName, $fieldName)
    {
        return isset($this->meta[$fieldSetName]['children'][$fieldName])
            ? $this->meta[$fieldSetName]['children'][$fieldName]
            : [];
    }

    /**
     * @inheritdoc
     */
    public function addFilter(\Magento\Framework\Api\Filter $filter)
    {
        $this->searchCriteriaBuilder->addFilter($filter);
    }

    /**
     * self::setOrder() alias
     *
     * @param string $field
     * @param string $direction
     * @return void
     */
    public function addOrder($field, $direction)
    {
        $this->searchCriteriaBuilder->addSortOrder($field, $direction);
    }

    /**
     * Set Query limit
     *
     * @param int $offset
     * @param int $size
     * @return void
     */
    public function setLimit($offset, $size)
    {
        $this->searchCriteriaBuilder->setPageSize($size);
        $this->searchCriteriaBuilder->setCurrentPage($offset);
    }

    /**
     * @param SearchResultInterface $searchResult
     * @return array
     */
    protected function searchResultToOutput(SearchResultInterface $searchResult)
    {
        $arrItems = [];
        $arr = [];

        $arrItems['items'] = [];
        foreach ($searchResult->getItems() as $item) {
            $itemData = [];
            foreach ($item->getCustomAttributes() as $attribute) {
                $itemData[$attribute->getAttributeCode()] = $attribute->getValue();
            }
			$arrItems['items'][] = $itemData;
        }

        $arrItems['totalRecords'] = $searchResult->getTotalCount();

        return $arrItems;
    }

    /**
     * Returns search criteria
     *
     * @return \Magento\Framework\Api\Search\SearchCriteria
     */
    public function getSearchCriteria()
    {
        if (!$this->searchCriteria) {
            $this->searchCriteria = $this->searchCriteriaBuilder->create();
            $this->searchCriteria->setRequestName($this->name);
        }
        return $this->searchCriteria;
    }

    /**
     * Get data
     *
     * @return array
     */
    public function getData()
    {
        return $this->searchResultToOutput($this->getSearchResult());
    }

    /**
     * Get config data
     *
     * @return array
     */
    public function getConfigData()
    {
        return isset($this->data['config']) ? $this->data['config'] : [];
    }

    /**
     * Set data
     *
     * @param mixed $config
     * @return void
     */
    public function setConfigData($config)
    {
        $this->data['config'] = $config;
    }

    /**
     * Returns Search result
     *
     * @return SearchResultInterface
     */
    public function getSearchResult()
    {
        return $this->reporting->search($this->getSearchCriteria());
    }
}
As per defined in frontend di.xml file, we have to create SearchResult.php file inside Ui/DataProvider folder.
<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Magelearn\CodeSample\Ui\DataProvider;

use Magento\Framework\Api;
use Magento\Framework\Data\Collection\Db\FetchStrategyInterface as FetchStrategy;
use Magento\Framework\Data\Collection\EntityFactoryInterface as EntityFactory;
use Magento\Framework\Event\ManagerInterface as EventManager;
use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
use Psr\Log\LoggerInterface as Logger;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\App\ObjectManager;

/**
 * Class SearchResult
 * Generic Search Result
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class SearchResult extends AbstractCollection implements Api\Search\SearchResultInterface
{
    /**
     * @var Api\Search\AggregationInterface
     */
    protected $aggregations;

    /**
     * @var Api\Search\SearchCriteriaInterface
     */
    protected $searchCriteria;

    /**
     * @var int
     */
    protected $totalCount;

    /**
     * @var string class name of document
     */
    protected $document = Document::class;

    /**
     * @var ResourceConnection
     */
    private $resourceConnection;

    /**
     * @var string
     */
    private $identifierName;

    /**
     * SearchResult constructor.
     * @param EntityFactory $entityFactory
     * @param Logger $logger
     * @param FetchStrategy $fetchStrategy
     * @param EventManager $eventManager
     * @param string $mainTable
     * @param null|string $resourceModel
     * @param null|string $identifierName
     * @param null|string $connectionName
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function __construct(
        EntityFactory $entityFactory,
        Logger $logger,
        FetchStrategy $fetchStrategy,
        EventManager $eventManager,
        $mainTable,
        $resourceModel = null,
        $identifierName = null,
        $connectionName = null
    ) {
        $this->_init($this->document, $resourceModel);
        $this->setMainTable(true);
        if ($connectionName) {
            $connection  = $this->getResourceConnection()->getConnectionByName($connectionName);
        } else {
            $connection = $this->getResourceConnection()->getConnection();
        }
        $this->setMainTable($this->getResourceConnection()->getTableName($mainTable));
        $this->identifierName = $identifierName;
        parent::__construct(
            $entityFactory,
            $logger,
            $fetchStrategy,
            $eventManager,
            $connection,
            null
        );
        $this->_setIdFieldName($this->getIdentifierName());
    }

    /**
     * @deprecated 100.2.0
     * @return ResourceConnection
     */
    private function getResourceConnection()
    {
        if ($this->resourceConnection == null) {
            $this->resourceConnection = ObjectManager::getInstance()->get(ResourceConnection::class);
        }
        return $this->resourceConnection;
    }

    /**
     * @return \Magento\Framework\Api\Search\AggregationInterface
     */
    public function getAggregations()
    {
        return $this->aggregations;
    }

    /**
     *  Get resource instance
     *
     * @return ResourceConnection|\Magento\Framework\Model\ResourceModel\Db\AbstractDb
     */
    public function getResource()
    {
        if ($this->_resourceModel) {
            return parent::getResource();
        }
        return $this->getResourceConnection();
    }

    /**
     * @param \Magento\Framework\Api\Search\AggregationInterface $aggregations
     * @return void
     */
    public function setAggregations($aggregations)
    {
        $this->aggregations = $aggregations;
    }

    /**
     * @return \Magento\Framework\Api\Search\SearchCriteriaInterface|null
     */
    public function getSearchCriteria()
    {
        return $this->searchCriteria;
    }

    /**
     * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria
     * @return $this
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function setSearchCriteria(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria)
    {
        $this->searchCriteria = $searchCriteria;
        return $this;
    }

    /**
     * @return int
     */
    public function getTotalCount()
    {
        if (!$this->totalCount) {
            $this->totalCount = $this->getSize();
        }
        return $this->totalCount;
    }

    /**
     * @param int $totalCount
     * @return $this
     */
    public function setTotalCount($totalCount)
    {
        $this->totalCount = $totalCount;
        return $this;
    }

    /**
     * Set items list.
     *
     * @param Document[] $items
     * @return $this
     */
    public function setItems(array $items = null)
    {
        if ($items) {
            foreach ($items as $item) {
                $this->addItem($item);
            }
            unset($this->totalCount);
        }
        return $this;
    }

    /**
     * Retrieve table name
     *
     * @param string $table
     * @return string
     */
    public function getTable($table)
    {
        return $this->getResourceConnection()->getTableName($table);
    }

    /**
     * Get Identifier name
     *
     * @return string|bool
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    private function getIdentifierName()
    {
        if ($this->_resourceModel) {
            return $this->getResource()->getIdFieldName();
        } elseif ($this->identifierName !== null) {
            return $this->identifierName;
        } else {
            return $this->getResourceConnection()->getConnection()->getAutoIncrementField($this->getMainTable());
        }
    }

    /**
     * Initialize initial fields to select like id field
     *
     * @return $this
     */
    protected function _initInitialFieldsToSelect()
    {
        $idFieldName = $this->getIdentifierName();
        if ($idFieldName) {
            $this->_initialFieldsToSelect[] = $idFieldName;
        }
        return $this;
    }

    /**
     * Retrieve all ids for collection
     *
     * @return array
     */
    public function getAllIds()
    {
        $idsSelect = clone $this->getSelect();
        $idsSelect->reset(\Magento\Framework\DB\Select::ORDER);
        $idsSelect->reset(\Magento\Framework\DB\Select::LIMIT_COUNT);
        $idsSelect->reset(\Magento\Framework\DB\Select::LIMIT_OFFSET);
        $idsSelect->reset(\Magento\Framework\DB\Select::COLUMNS);
        $idsSelect->columns($this->getIdentifierName(), 'main_table');
        return $this->getConnection()->fetchCol($idsSelect, $this->_bindParams);
    }
}
As per code highlighted in above file we have to create Document.php inside Ui/DataProvider folder.
<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Magelearn\CodeSample\Ui\DataProvider;

use Magento\Framework\Api\Search\DocumentInterface;
use Magento\Framework\DataObject;
use Magento\Framework\Api\AttributeValueFactory;

/**
 * Class Document
 */
class Document extends DataObject implements DocumentInterface
{
    /**
     * @var string|int
     */
    protected $id;

    /**
     * @var AttributeValueFactory
     */
    protected $attributeValueFactory;

    /**
     * @param AttributeValueFactory $attributeValueFactory
     */
    public function __construct(AttributeValueFactory $attributeValueFactory)
    {
        $this->attributeValueFactory = $attributeValueFactory;
    }

    /**
     * @return int|string
     */
    public function getId()
    {
        if (!$this->id) {
            $this->id = $this->getData($this->getIdFieldName());
        }
        return $this->id;
    }

    /**
     * @param int $id
     * @return void
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * Get an attribute value.
     *
     * @param string $attributeCode
     * @return \Magento\Framework\Api\AttributeInterface|null
     */
    public function getCustomAttribute($attributeCode)
    {
        /** @var \Magento\Framework\Api\AttributeInterface $attributeValue */
        $attributeValue = $this->attributeValueFactory->create();
        $attributeValue->setAttributeCode($attributeCode);
        $attributeValue->setValue($this->getData($attributeCode));
        return $attributeValue;
    }

    /**
     * Set an attribute value for a given attribute code
     *
     * @param string $attributeCode
     * @param mixed $attributeValue
     * @return $this
     */
    public function setCustomAttribute($attributeCode, $attributeValue)
    {
        $this->setData($attributeCode, $attributeValue);
        return $this;
    }

    /**
     * Retrieve custom attributes values.
     *
     * @return \Magento\Framework\Api\AttributeInterface[]|null
     */
    public function getCustomAttributes()
    {
        $output = [];
        foreach ($this->getData() as $key => $value) {
            $attribute = $this->attributeValueFactory->create();
            $output[] = $attribute->setAttributeCode($key)->setValue($value);
        }
        return $output;
    }

    /**
     * Set array of custom attributes
     *
     * @param \Magento\Framework\Api\AttributeInterface[] $attributes
     * @return $this
     * @throws \LogicException
     */
    public function setCustomAttributes(array $attributes)
    {
        /** @var \Magento\Framework\Api\AttributeInterface $attribute */
        foreach ($attributes as $attribute) {
            $this->setData(
                $attribute->getAttributeCode(),
                $attribute->getValue()
            );
        }
        return $this;
    }
}
As per defined in frontend layout file codesample_index_index.xml file, we will add our backend.less file.

These file include all the necessary files and folders css and fonts, to display admin grid on front end properly.

Hope you like this article. Happy coding 😊

1 Comments On "Magento2 Admin grid with product selection ui_component and display data with Knockout JS on frontend."

Thanks for the valuable Content. It will useful for knowledge seekers. Keep sharing your knowledge through this kind of article.
IELTS Speaking Tips
IELTS Speaking Test Tips

Back To Top