UI component is designed for rendering a User Interface in a simple and flexible way.  It enables a connection between the UI  visual elements and the related data process submitted by users.

 

In this Magento Developer Guide, I will guide you on how to use UI component to create UI Form in Magento 2.

 

The prerequisites:

 

- Set up module

 

- Set up table

 

- Set up 3 files: model, resourcemodel, and collection

 

- Set up controller and layout filet. In layout file, a reference to a file ui component is ui_component/my_form.xml

 

File content <routes>_<controller>_<action>.xml

(ex: magenest_myform_index.xml)

 

<?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="my_form" /> 
</referenceContainer> 
</body> 
</page>

 

Create the corresponding ui_component file named my_form.xml

 

Content file ui_component / my_form.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<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">my_form.my_form_data_source</item>
<item name="deps" xsi:type="string">my_form.my_form_data_source</item>
</item>
<item name="label" xsi:type="string" translate="true">Information</item>
<item name="config" xsi:type="array">
<item name="dataScope" xsi:type="string">data</item>
<item name="namespace" xsi:type="string">my_form</item>
</item>
<item name="template" xsi:type="string">templates/form/collapsible</item>
<item name="buttons" xsi:type="array"> 
<item name="back" xsi:type="string">Magenest\MyForm\Block\Adminhtml\Form\Edit\BackButton</item> 
<item name="delete" xsi:type="string">Magenest\MyForm\Block\Adminhtml\Form\Edit\DeleteButton</item> 
<item name="reset" xsi:type="string">Magenest\MyForm\Block\Adminhtml\Form\Edit\ResetButton</item> 
<item name="save" xsi:type="string">Magenest\MyForm\Block\Adminhtml\Form\Edit\SaveButton</item> 
</item>
</argument>
<dataSource name="my_form_data_source">
<argument name="dataProvider" xsi:type="configurableObject">
<argument name="class" xsi:type="string">Magenest\MyForm\UiComponent\DataProvider</argument>
<argument name="name" xsi:type="string">my_form_data_source</argument>
<argument name="primaryFieldName" xsi:type="string">id</argument>
<argument name="requestFieldName" xsi:type="string">id</argument>
<argument name="data" xsi:type="array"> 
<item name="config" xsi:type="array"> 
<item name="submit_url" xsi:type="url" path="magenest/myform/save" /> 
</item> 
</argument>
</argument>
<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>
</dataSource>
<fieldset name="my_form_fieldset">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="collapsible" xsi:type="boolean">true</item>
<item name="label" xsi:type="string" translate="true">Fieldset Label</item>
<item name="sortOrder" xsi:type="number">0</item>
</item>
</argument>
<field name="id">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="dataType" xsi:type="string">text</item>
<item name="label" xsi:type="string" translate="true">Id</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">my_form</item>
<item name="dataScope" xsi:type="string">id</item>
</item>
</argument>
</field>
<field name="name">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="dataType" xsi:type="string">text</item>
<item name="label" xsi:type="string" translate="true">Name</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">my_form</item>
<item name="dataScope" xsi:type="string">name</item>
</item>
</argument>
</field>
<field name="description">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="dataType" xsi:type="string">text</item>
<item name="label" xsi:type="string" translate="true">Description</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">my_form</item>
<item name="dataScope" xsi:type="string">description</item>
</item>
</argument>
</field>
</fieldset>
</form>

 

4 button files

 

4 button files can be declared with the following content:

 

BackButton.php

 

<?php 
namespace Magenest\MyForm\Block\Adminhtml\Form\Edit; 

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

class BackButton extends GenericButton implements ButtonProviderInterface 
{ 
public function getButtonData() 
{ 
return [ 
'label' => __('Back'), 
'on_click' => sprintf("location.href= '%s';", $this->getBackUrl()), 
'class' => 'back', 
'sort_order' => 10 ]; 
} 

public function getBackUrl() { return $this->getUrl('*/*/'); } 
}

 

DeleteButton.php

 

<?php 
namespace Magenest\MyForm\Block\Adminhtml\Form\Edit; 

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

class DeleteButton extends GenericButton implements ButtonProviderInterface { 
public function getButtonData()
{ 
return [ 
'label' => __('Delete Contact'), 
'on_click' => 'deleteConfirm(\'' . __('Are you sure you want to delete this contact ?') . '\', \'' . $this->getDeleteUrl() . '\')', 
'class' => 'delete', 
'sort_order' => 20 
]; 
} 

public function getDeleteUrl() { 
$id = $this->request->getParam('id');
return $this->getUrl('*/*/delete', ['id' => $id]); 
} 
}

 

ResetButton.php

 

<?php 
namespace Magenest\MyForm\Block\Adminhtml\Form\Edit; 

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

class ResetButton extends GenericButton implements ButtonProviderInterface { 
public function getButtonData() 
{ 
return [ 
'label' => __('Reset'), 
'on_click' => 'javascript: location.reload();', 'class' => 'reset', 'sort_order' => 30 ]; 
} 
}

 

SaveButton.php

 

<?php 
namespace Magenest\MyForm\Block\Adminhtml\Contact\Edit; 

use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface; class SaveButton extends GenericButton implements ButtonProviderInterface 
{ 
public function getButtonData() 
{ 
return [ 
'label' => __('Save Contact'), 
'class' => 'save primary', 
'data_attribute' => [ 
'mage-init' => [
'button' => ['event' => 'save']], 
'form-role' => 'save', 
], 
'sort_order' => 90 ];
}
public function getSaveUrl() 
{ 
return $this->getUrl('*/*/save', []) ; 
} 
}

 

It includes 3 nodes: argument, dataSource, and fieldset.

 

Argument node needs to declare the name as data, be able to set file template (such as html or xhtml), file component  (js), label, dataprovider, dependencies, datascope, namespace, etc.

 

dataSource node define a datasource, datasource needn’t template, but it is still a component and need to set a link to file component (js).

 

Besides, dataSource need an argument whose name is dataProvider, this argument is a configurableObject (php object), dataProvider is used to retrieve data from the database.

 

Class dataProvider need to implement this interface:

 

\Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface.

 

The best is to extend this class:

 

Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider

 

In this class, need add-on primaryFieldName parameters into __construct, requestFieldName corresponds to file my_form.xml. In addition, it is necessary to set the corresponding collection.

 

Fieldset node defines fields. Besides basic fields, a custom field can be written, set component and template.

 

Examples about custom field:

 

1. File CSV uploader:

 

<field name="category"> 
<argument name="data" xsi:type="array"> 
<item name="config" xsi:type="array"> 
<item name="sortOrder" xsi:type="number">10</item> 
<item name="label" xsi:type="string">My CSV</item> 
<item name="visible" xsi:type="boolean">true</item> 
<item name="formElement" xsi:type="string">fileUploader</item> 
<item name="template" xsi:type="string">Magenest_Myform/file-uploader</item> 
<item name="allowedExtensions" xsi:type="string">csv</item> 
<item name="maxFileSize" xsi:type="number">20000000</item> 
<item name="uploaderConfig" xsi:type="array"> 
<item name="url" xsi:type="url" path="magenest/form/uploader"/> 
</item> 
<item name="validation" xsi:type="array"> 
<item name="required-entry" xsi:type="string">true</item> 
</item> 
</item> 
</argument> 
</field>


 

In detail:

 

- formElement declares element type of this field (here declares fileUploader).

 

- template declares layout template of this field. This file template will be placed in file

 

<vendor>/<module>/view/adminhtml/web/template.

 

- alllowedExtensions declares uploaded file types (here is file csv type).

 

- uploaderConfig declares configuration of uploader. For instance, we will declare link to controller to process upload file by url tag.

 

- validation declares conditions to approve datakhai. We also declare required-entry which means user had to data in this field.

 

File template for uploader:

 

<div class="admin__field" visible="visible" css="$data.additionalClasses"> <label class="admin__field-label" if="$data.label" attr="for: uid"> 
<span translate="label" attr="'data-config-scope': $data.scopeLabel"/> </label> 
<div class="admin__field-control" css="'_with-tooltip': $data.tooltip"> <div class="file-uploader" data-role="drop-zone" css="_loading: isLoading"> <div class="file-uploader-area"> 
<input type="file" afterRender="onElementRender" attr="id: uid, name: inputName, multiple: isMultipleFiles, accept: '.'+ allowedExtensions" disable="disabled" /> 
<label class="file-uploader-button action-default" attr="for: uid" translate="'Upload'"/> 
<span class="file-uploader-spinner"/> 
<render args="fallbackResetTpl" if="$data.showFallbackReset && $data.isDifferedFromDefault"/> 
</div> 
<render args="tooltipTpl" if="$data.tooltip"/> 
<div class="admin__field-note" if="$data.notice" attr="id: noticeId"> 
<span html="notice"/> 
</div> 
<label class="admin__field-error" if="error" attr="for: uid" text="error"/> <each args="data: value, as: '$file'" render="$parent.getPreviewTmpl($file)"/> 
<div if="isMultipleFiles" class="file-uploader-summary"> 
<label attr="for: uid" class="file-uploader-placeholder" css="'placeholder-' + placeholderType"> 
<span class="file-uploader-placeholder-text" translate="'Click here or drag and drop to add files.'"/> 
</label> 
</div> 
</div> 
<render args="$data.service.template" if="$data.hasService()"/> 
</div> 
</div>

 

  2. Add custom validation rule for a field:

 

<field name="custom"> 
<argument name="data" xsi:type="array"> 
<item name="config" xsi:type="array">
<item name="component" xsi:type="string">Magenest_MyForm/js/custom-rule</item> 
<item name="dataType" xsi:type="string">text</item> 
<item name="label" xsi:type="string" translate="true">Custom Rule</item>
<item name="formElement" xsi:type="string">input</item> 
<item name="sortOrder" xsi:type="number">20</item> 
<item name="validation" xsi:type="array"> 
<item name="custom-validate-rule" xsi:type="boolean">true</item> 
</item> 
</item> 
</argument> 
</field>

 

Initially, we define our own component to handle the logic for this field.

 

,Magenest_MyForm/js/custom-rule. This file places in  <vendor>/<module>/view/adminhtml/web/js/custom-rule.js.

 

Next, we declare the custom rule using for this field at validation tags, particularly rule "custom-validate-rule"

 

Component file sample:

 

define([
    'jquery',
    'Magento_Ui/js/form/element/abstract',
    'Magento_Ui/js/lib/validation/validator',
], function ($, Abstract, validator) {
    'use strict';

    return Abstract.extend({
        initialize: function () {
            var self = this;
            this._super();

            validator.addRule(
                'custom-validate-rule',
                function (value, element) {
                    //Your conditions
                },
                $.mage.__('Error message')
            );
            return this;
        }
    });
});

 

I hope that creating a form using UI component in Magento 2 will become easier after you read the instruction in this blog.

 

If you have any questions, feel free to leave your comments below.