This tutorial is the 7th in a long series of magento2 tutorial. In the last episode, you learned how to create a model and interact with the magento2 database. If you do not know magento (v1) it does not matter, I will talk about it but you do not need to know the magento (v1) platform to master this tutorial on magento2.But you have to do the 6 previous tutorials before starting this one.
In the previous tutorial we saw how to add its module to the administration (backend) of magento2! We will now see
how to add a grid and a form magento2. We'll implemente the CRUD (adding, modifying, deleting, mass deletion) for our contacts. Let start from the files in our previous tutorial.
Create the controller for the grid magento2
First of all, we will
create our magento2 grid which will allow us to view our contacts in the backend. To do this, start by editing the Index action of your Contact controller (/Pfay/Contacts/Controller/Adminhtml/Test/Index.php) like this to load and display your layout:
namespace Pfay\Contacts\Controller\Adminhtml\Test;
class Index extends \Magento\Backend\App\Action
{
/**
* Index action
*
* @return void
*/
public function execute()
{
$this->_view->loadLayout();
$this->_view->renderLayout();
}
}
Create the layout file of the magento2 grid and the uiComponent "listing"
Create the layout file /Pfay/Contacts/view/adminhtml/layout/contacts_test_index.xml Like this :
<?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">
<body>
<referenceContainer name="content">
<uiComponent name="contacts_test_listing"/>
</referenceContainer>
</body>
</page>
Here it is told to get
uiComponent and put it in the container "content" of our theme. We will give it the name "contacts_test_listing" (pay attention to the name you give here because we will use it to create the following file).
This magento2 uiComponent is as you can imagine our Grid.
So we will define our uiComponent.
Create the /app/code/Pfay/Contacts/view/adminhtml/ui_component/ folder with the following contacts_test_listing.xml file:
<?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">
<!-- main part of the grid -->
<argument name="data" xsi:type="array">
<!-- define where to find the date source -->
<item name="js_config" xsi:type="array">
<item name="provider" xsi:type="string">contacts_test_listing.contacts_test_listing_data_source</item>
<item name="deps" xsi:type="string">contacts_test_listing.contacts_test_listing_data_source</item>
</item>
<!-- define where to find the columns -->
<item name="spinner" xsi:type="string">contacts_test_columns</item>
<item name="buttons" xsi:type="array">
<item name="add" xsi:type="array">
<item name="name" xsi:type="string">add</item>
<item name="label" xsi:type="string" translate="true">Add a new Contact</item>
<item name="class" xsi:type="string">primary</item>
<item name="url" xsi:type="string">*/*/newAction</item>
</item>
</item>
</argument>
<!-- define the date source (must be the same than in argument/item/provider and argument/js_config/deps -->
<dataSource name="contacts_contact_data_source">
<argument name="dataProvider" xsi:type="configurableObject">
<!-- unique name for the grid -->
<argument name="class" xsi:type="string">ContactsGridDataProvider</argument>
<!-- name of the data source same as in argument/js_config/provider -->
<argument name="name" xsi:type="string">contacts_test_listing_data_source</argument>
<argument name="primaryFieldName" xsi:type="string">pfay_contacts_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="mui/index/render"/>
<item name="storageConfig" xsi:type="array">
<item name="indexField" xsi:type="string">pfay_contacts_id</item>
</item>
</item>
</argument>
</argument>
</dataSource>
<!-- define the columns of my grid -->
<columns name="contacts_test_columns">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<!-- Bookmarks behaviour -->
<item name="storageConfig" xsi:type="array">
<item name="provider" xsi:type="string">contacts_test_listing.contacts_test_listing.listing_top.bookmarks</item>
<item name="namespace" xsi:type="string">current</item>
</item>
<item name="childDefaults" xsi:type="array">
<item name="controlVisibility" xsi:type="boolean">true</item>
<item name="storageConfig" xsi:type="array">
<item name="provider" xsi:type="string">contacts_test_listing.contacts_test_listing.listing_top.bookmarks</item>
<item name="root" xsi:type="string">columns.${ $.index }</item>
<item name="namespace" xsi:type="string">current.${ $.storageConfig.root}</item>
</item>
</item>
</item>
</argument>
<selectionsColumn name="ids">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<!-- define which field will be used as ID -->
<item name="indexField" xsi:type="string">pfay_contacts_id</item>
</item>
</argument>
</selectionsColumn>
<!-- Column ID -->
<column name="pfay_contacts_id">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="filter" xsi:type="string">textRange</item>
<item name="sorting" xsi:type="string">asc</item>
<item name="label" xsi:type="string" translate="true">ID</item>
</item>
</argument>
</column>
<!-- Column name -->
<column name="name">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="visible" xsi:type="boolean">true</item>
<item name="dataType" xsi:type="string">text</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">contact</item>
<item name="dataScope" xsi:type="string">name</item>
<item name="label" xsi:type="string" translate="true">Name</item>
<item name="filter" xsi:type="string">text</item>
<item name="validation" xsi:type="array">
<item name="required-entry" xsi:type="boolean">true</item>
</item>
</item>
</argument>
</column>
<!-- Column email -->
<column name="email">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="visible" xsi:type="boolean">true</item>
<item name="dataType" xsi:type="string">text</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">contact</item>
<item name="dataScope" xsi:type="string">email</item>
<item name="label" xsi:type="string" translate="true">Email</item>
<item name="filter" xsi:type="string">text</item>
<item name="validation" xsi:type="array">
<item name="required-entry" xsi:type="boolean">true</item>
</item>
</item>
</argument>
</column>
<!-- action columns edit and delete -->
<actionsColumn name="actions" class="Pfay\Contacts\Ui\Component\Listing\Column\ContactsActions">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="resizeEnabled" xsi:type="boolean">false</item>
<item name="resizeDefaultWidth" xsi:type="string">107</item>
<item name="indexField" xsi:type="string">pfay_contacts_id</item>
</item>
</argument>
</actionsColumn>
</columns>
</listing>
This file looks complex but it is not as complex as it seems.It is just a listing tag that contains 4 child tags:
-
argument:
Here we declare the data_sources to use (which makes the links between your grid and the database) with the tag js_config.
We also declare the spinner, that is the name of the tag "columns" that will be used in our grid.
We then declare our buttons in the buttons tag with a name, a label, a class and a target url.
-
dataSource:
Here we define the
dataProvider (the object that will fetch our data in database). With a "class" tag to define the name of the object to be used. This object will be defined later in the di.xml (dependency node file).
We give a name to our dataSource via the "name" attribute and then we give it the field to use as the id for the grid in the database ("primaryFieldName") and for the request ("requestFieldName").
We then define in "config" the component to use (here "Magento_Ui/js/grid/provider") and the identifier in our bdd "indexField" which here has the value "pfay_contacts_id".
-
columns:
It was defined above in the "spinner" section of the "argument" section, here it is named listing_columns.
This area will allow us to define our columns with the identifier to be used to find oneself, the type of fields and filters to use for the grid, the type of sorting that will be used and a label.
In the actionsColumn we defined the class to use to define the buttons to know ContactsActions. Therefore, create the corresponding app/code/Pfay/Contacts/Ui/Component/Listing/Column/ContactsActions.php file:
<?php
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Pfay\Contacts\Ui\Component\Listing\Column;
use Magento\Framework\View\Element\UiComponent\ContextInterface;
use Magento\Framework\View\Element\UiComponentFactory;
use Magento\Ui\Component\Listing\Columns\Column;
use Magento\Framework\UrlInterface;
/**
* Class DepartmentActions
*/
class ContactsActions extends Column
{
/**
* @var UrlInterface
*/
protected $urlBuilder;
/**
* @param ContextInterface $context
* @param UiComponentFactory $uiComponentFactory
* @param UrlInterface $urlBuilder
* @param array $components
* @param array $data
*/
public function __construct(
ContextInterface $context,
UiComponentFactory $uiComponentFactory,
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) {
$item[$this->getData('name')]['edit'] = [
'href' => $this->urlBuilder->getUrl(
'contacts/test/edit',
['id' => $item['pfay_contacts_id']]
),
'label' => __('Edit'),
'hidden' => false,
];
$item[$this->getData('name')]['delete'] = [
'href' => $this->urlBuilder->getUrl(
'contacts/test/delete',
['id' => $item['pfay_contacts_id']]
),
'label' => __('Delete'),
'hidden' => false,
];
}
}
return $dataSource;
}
}
That's all..for the moment, it was not so complicated..you see :)
Then remember that in this file we defined an object called ContactsGridDataProvider, currently it does not correspond to anything so we will declare this object called a dataProvider by defining it in the dependency injection file (di. Xml).
So create the app/code/Pfay/Contacts/etc/di.xml file like this:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<virtualType name="ContactsGridDataProvider" type="Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider">
<arguments>
<argument name="collection" xsi:type="object" shared="false">Pfay\Contacts\Model\ResourceModel\Contact\Collection</argument>
<argument name="filterPool" xsi:type="object" shared="false">ContactsGirdFilterPool</argument>
</arguments>
</virtualType>
<virtualType name="ContactsGridDataProvider" type="Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider">
<arguments>
<argument name="collection" xsi:type="object" shared="false">Pfay\Contacts\Model\ResourceModel\Contact\Collection</argument>
<argument name="filterPool" xsi:type="object" shared="false">ContactsGirdFilterPool</argument>
</arguments>
</virtualType>
<virtualType name="ContactsGirdFilterPool" type="Magento\Framework\View\Element\UiComponent\DataProvider\FilterPool">
<arguments>
<argument name="appliers" xsi:type="array">
<item name="regular" xsi:type="object">Magento\Framework\View\Element\UiComponent\DataProvider\RegularFilter</item>
<item name="fulltext" xsi:type="object">Magento\Framework\View\Element\UiComponent\DataProvider\FulltextFilter</item>
</argument>
</arguments>
</virtualType>
<type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
<arguments>
<argument name="collections" xsi:type="array">
<item name="contacts_test_listing_data_source" xsi:type="string">Pfay\Contacts\Model\ResourceModel\Contact\Collection</item>
</argument>
</arguments>
</type>
<virtualType name="Pfay\Contacts\Model\ResourceModel\Contact\Collection" type="Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult">
<arguments>
<argument name="mainTable" xsi:type="string">pfay_contacts</argument>
<argument name="resourceModel" xsi:type="string">Pfay\Contacts\Model\ResourceModel\Contact</argument>
</arguments>
</virtualType>
</config>
Here it looks like it is complicated but in fact it is very simple:
1- We define a virtualType ContactsGridDataProvider, we pass it to the class of our collection Pfay\Contacts\Model\ResourceModel\Contact\Collection and we tell magento to use a "filterPool" with the name "ContactsGirdFilterPool".
2- We define the "ContactsGirdFilterPool" just declared by passing a item "regular" and a item "fulltext".
3- we create the type contacts_test_listing_data_source that we use above in our XML (be careful to put the same name) and we define that it will use our collection.
4. Create a VirtualType SearchResult, pass it on to our collection, and tell it to use our "pfay_contacts" table and the resourceModel "Pfay\Contacts\Model\ResourceModel\Contact" to find out.
Go to your admin interface and you should now see your grid appears.
If this is not the case, do not hesitate to empty your cache, run the update command (see previous tutorials) and give the right rights to your files.
Add the add button to our magento2 grid
In our listing component (our grid : /app/code/Pfay/Contacts/view/adminhtml/ui_component/contacts_test_listing.xml) add the following code in argument to add the "add" button of our grid:
<item name="buttons" xsi:type="array">
<item name="add" xsi:type="array">
<item name="name" xsi:type="string">add</item>
<item name="label" xsi:type="string" translate="true">Add a new contact</item>
<item name="class" xsi:type="string">primary</item>
<item name="url" xsi:type="string">*/*/newAction</item>
</item>
</item>
It is in the item "buttons" that you will put all your buttons. This element is an "array", so you can put several items in a row.
Each element will be a button, for which you define a name, label, class and url. Which one is redirecting when clicked (here we redirect to */*/add which means that we will redirect To the "Add" action of the same folder as our current Action.
We create a file /app/code/Pfay/Contacts/Controller/Adminhtml/Test/Add.php that contains our action:
<?php
namespace Pfay\Contacts\Controller\Adminhtml\Test;
use Magento\Backend\App\Action;
class Add extends \Magento\Backend\App\Action
{
public function execute()
{
die('test add');
}
}
Reload your page and click on the "Add a new Contact" button that appears now, you should arrive on your action which displays a blank page with "test add".
We'll see in the next tutorial how to display the form that will add a new contact.
Optional items:
The optional elements are put in the "container". The "container" is the 4th non-mandatory tag of the listing element after "argument", "dataSource", and "columns" which are mandatory. It takes at least one data argument which allows to define its template ( ui/grid/toolbar ).
Here's how to integrate it into our /app/code/Pfay/Contacts/view/adminhtml/ui_component/contacts_test_listing.xml file
<container name="listing_top">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="template" xsi:type="string">ui/grid/toolbar</item>
</item>
</argument>
<!-- we put the others elements here -->
</container>
So this is
in this "container" element that we'll put the optional elements.Add the "columns controls" Container
The columns controls is an element that allows you to manage the columns of your grid on the fly, you can add/remove a column/reset the grid to a base state and you can save the grid state in the session.
Here is the code to integrate in the "container" to display the columns controls:
<container name="columns_controls">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="columnsData" xsi:type="array">
<item name="provider" xsi:type="string">contacts_test_listing.contacts_test_listing.contacts_test_columns</item>
</item>
<item name="component" xsi:type="string">Magento_Ui/js/grid/controls/columns</item>
<item name="displayArea" xsi:type="string">dataGridActions</item>
</item>
</argument>
</container>
The Bookmarks
The bookmarks allows you to save the state of the listing which you modified with the element "columns_control" previously created. Here is how to integrate the "bookmark" in the "container" :
<bookmark name="bookmarks">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="component" xsi:type="string">Magento_Ui/js/grid/controls/bookmarks/bookmarks</item>
<item name="displayArea" xsi:type="string">dataGridActions</item>
<item name="storageConfig" xsi:type="array">
<item name="saveUrl" xsi:type="url" path="*/*/save"/>
<item name="deleteUrl" xsi:type="url" path="*/*/delete"/>
<item name="namespace" xsi:type="string">contact_test_listing</item>
</item>
</item>
</argument>
</bookmark>
Be sure to put the namespace and define your urls.
Pagination
The pagination of the grid under magento2 is super well done and very easy to integrate, it is enough just to pay attention to the 2 paths "provider" and "selectProvider".
Here is the code to insert:
<paging name="listing_paging">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="storageConfig" xsi:type="array">
<!-- we put here the path to the bookmarks element -->
<item name="provider" xsi:type="string">contacts_test_listing.contacts_test_listing.listing_top.bookmarks</item>
<item name="namespace" xsi:type="string">current.paging</item>
</item>
<!-- we put here the path to the element pfay_contact_ids of contacts_test_columns element -->
<item name="selectProvider" xsi:type="string">contacts_test_listing.contacts_test_listing.contacts_test_columns.pfay_contacts_id</item>
<item name="displayArea" xsi:type="string">bottom</item>
</item>
</argument>
</paging>
Magento2 grid filters
To be able to filter the table can sometimes be practical, for that a "filter" element can be added to the magento grid. Here's how to do it:
<filters name="listing_filters">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="storageConfig" xsi:type="array">
<item name="provider" xsi:type="string">contacts_test_listing.contacts_test_listing.listing_top.bookmarks</item>
<item name="namespace" xsi:type="string">curren.filters</item>
</item>
<item name="childDefaults" xsi:type="array">
<item name="provider" xsi:type="string">contacts_test_listing.contacts_test_listing.listing_top.listing_filters</item>
<item name="imports" xsi:type="array">
<item name="visible" xsi:type="string">contacts_test_listing.contacts_test_listing.listing_top.bookmarks:current.columns.${ $.index }.visible</item>
</item>
</item>
</item>
</argument>
</filters>
By default, it takes all the fields available on the grid, it knows how to filter with the "filter" item of your "columns" like these:
ici type text :
<item name="filter" xsi:type="string">text</item>
ici type textRange :
<item name="filter" xsi:type="string">textRange</item>
Mass Actions under magento2
You want to be able to select several lines of your grid to delete them all at once or do another specific processing on all the lines selected at the same time? The Mass Actions are made for this.
First of all it will be necessary to add the inputs on the edge of our grid to be able to select the lines, so in "columns" add this before the "column":
<selectionsColumn name="ids">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<!-- define which field will be used as ID -->
<item name="indexField" xsi:type="string">pfay_contacts_id</item>
</item>
</argument>
</selectionsColumn>
You now see the checkboxes on the side that allow you to select multiple lines.
Here is how to integrate the selectbox which allows to select the action to be performed once we have selected our lines:
<massaction name="listing_massaction">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<!-- we put here the path to the element pfay_contact_ids of contacts_test_columns element -->
<item name="selectProvider" xsi:type="string">contacts_test_listing.contacts_test_listing.contacts_test_columns.ids</item>
<item name="displayArea" xsi:type="string">bottom</item>
<item name="indexField" xsi:type="string">pfay_contacts_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 Selected</item>
<item name="url" xsi:type="url" path="*/*/massDelete"/>
<item name="confirm" xsi:type="array">
<item name="title" xsi:type="string" translate="true">Delete all selected contacts</item>
<item name="message" xsi:type="string" translate="true">Do you want to delete all the selected contacts?</item>
</item>
</item>
</argument>
</action>
</massaction>
Here it is the same, we have to be careful on what we enter as a path for the "selectProvider" and we add the actions following each other. In order to prepare the next tutorial, we will create the MassDelete controller. This is where we will be redirected when we select our action (*/*/massDelete).
Create the following file /app/code/Pfay/Contacts/Controller/Adminhtml/Test/MassDelete.php :
<?php
namespace Pfay\Contacts\Controller\Adminhtml\Test;
use Magento\Backend\App\Action;
use Pfay\Contacts\Model\Contact;
class MassDelete extends \Magento\Backend\App\Action
{
public function execute()
{
$ids = $this->getRequest()->getParam('selected', []);
if (!is_array($ids) || !count($ids)) {
$resultRedirect = $this->resultRedirectFactory->create();
return $resultRedirect->setPath('*/*/index', array('_current' => true));
}
foreach ($ids as $id) {
if ($contact = $this->_objectManager->create(Contact::class)->load($id)) {
$contact->delete();
}
}
$this->messageManager->addSuccess(__('A total of %1 record(s) have been deleted.', count($ids)));
$resultRedirect = $this->resultRedirectFactory->create();
return $resultRedirect->setPath('*/*/index', array('_current' => true));
}
}
Here we check that the parameter "selected" has indeed been sent and that it is indeed a non-empty array otherwise we redirect to the grid. If it's ok, then we go through the ids and delete the contacts. Then we redirect to the grid.
And voila if you use your mass actions you should arrive on your action.
Create a search field in admin magento2
To create a search field on the magento admin, you must add an optional element in the container that will be called "filterSearch" like this:
In app/code/Pfay/Contacts/view/adminhtml/ui_component/contacts_test_listing.xml you can add:
<!-- Filter Search -->
<filterSearch name="fulltext">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="provider" xsi:type="string">contacts_test_listing.contacts_test_listing_data_source</item>
<item name="chipsProvider" xsi:type="string">contacts_test_listing.contacts_test_listing.listing_top.listing_filters_chips</item>
<item name="storageConfig" xsi:type="array">
<item name="provider" xsi:type="string">contacts_test_listing.contacts_test_listing.listing_top.bookmarks</item>
<item name="namespace" xsi:type="string">current.search</item>
</item>
</item>
</argument>
</filterSearch>
For the searchbar to work you have to update your table to add the index.
So edit your upgrade file (app/code/Pfay/Contacts/Setup/UpgradeSchema.php) like this:
<?php
namespace Pfay\Contacts\Setup;
use Magento\Framework\Setup\UpgradeSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Catalog\Model\ResourceModel\Product\Gallery;
use Magento\Catalog\Model\Product\Attribute\Backend\Media\ImageEntryConverter;
/**
* Upgrade the Catalog module DB scheme
*/
class UpgradeSchema implements UpgradeSchemaInterface
{
/**
* {@inheritdoc}
*/
public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context)
{
$setup->startSetup();
if (version_compare($context->getVersion(), '0.2.0', '<')) {
$tableName = $setup->getTable('pfay_contacts');
$setup->getConnection()->addColumn($tableName, 'comment', [
'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'length' => 255,
'unsigned' => true,
'nullable' => false,
'default' => '0',
'comment' => 'Comment'
]);
}else if (version_compare($context->getVersion(), '0.3.0', '<')) {
/**
* Add full text index to our table department
*/
$tableName = $setup->getTable('pfay_contacts');
$fullTextIntex = array('name','email'); // Column with fulltext index, you can put multiple fields
$setup->getConnection()->addIndex(
$tableName,
$setup->getIdxName($tableName, $fullTextIntex, \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_FULLTEXT),
$fullTextIntex,
\Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_FULLTEXT
);
}
$setup->endSetup();
}
}
You notice here that for version 0.3.0, we add for the table pfay_contacts an index on the name and the email of type FULLTEXT. It is this index that will be used to filter our admin listing in magento2.
We will see in the next tutorial how to create the create/delete/edit actions and the creation and editing form linked to our grid and our contact object!
This is the end of this tutorial on magento2 uiComponent listing, congratulations to you who followed this tutorial until the end. If this tutorial tells you more or you have a question, share this article on twitter and don't hesitate to let a comment!