Magento – uicomponent form add new button for modal

adminhtmlmagento-2.1uicomponent

I have build a custom form using uicomponent I want to add a button and on click want to open a modal with product grid.

How can I achieve this using uicomponent form ?

Best Answer

I have created a similar feature to assign categories via popup.

My Custom Product Grid (below) where I have inserted a modal with UI-grid with opens on click on the column category.

You can use insertForm instead of insertListing (mymodule_mycategory_listing) for your form.

Product Grid:

<?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">
    <!-- listingToolbar, dataSource, etc components same as product grid    -->
    <columns name="product_columns" class="Magento\Catalog\Ui\Component\Listing\Columns">
        <actionsColumn name="product_category" class="MyVendor\MyModule\Ui\Component\Listing\Columns\Product\Category">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="component" xsi:type="string">MyVendor_MyModule/js/grid/columns/product/category/assign</item>
                    <item name="label" xsi:type="string" translate="true">Category</item>
                    <item name="indexField" xsi:type="string">id</item>
                    <item name="urlEntityParamName" xsi:type="string">id</item>
                    <item name="sortOrder" xsi:type="number">1000</item>
                </item>
            </argument>
        </actionsColumn>
    </columns>
    <modal name="assign_category_modal">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="options" xsi:type="array">
                    <item name="buttons" xsi:type="array">
                        <item name="0" xsi:type="array">
                            <item name="text" xsi:type="string">Cancel</item>
                            <item name="class" xsi:type="string">action-secondary</item>
                            <item name="actions" xsi:type="array">
                                <item name="0" xsi:type="string">actionCancel</item>
                            </item>
                        </item>
                        <item name="1" xsi:type="array">
                            <item name="text" xsi:type="string">Assign Category</item>
                            <item name="class" xsi:type="string">action-primary save</item>
                            <item name="actions" xsi:type="array">
                                <item name="0" xsi:type="array">
                                    <item name="targetName" xsi:type="string">myvendor_mymodule_myproductgrid.myvendor_mymodule_myproductgrid.assign_category_modal.general.insertListing</item>
                                    <item name="actionName" xsi:type="string">save</item>
                                </item>
                                <item name="1" xsi:type="string">closeModal</item>
                            </item>
                        </item>
                    </item>
                </item>
            </item>
        </argument>
        <fieldset name="general">
            <settings>
                <label/>
            </settings>
            <insertListing>
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="component" xsi:type="string">Magento_Ui/js/form/components/insert-listing</item>
                        <item name="autoRender" xsi:type="string">true</item>
                        <item name="ns" xsi:type="string">mymodule_mycategory_listing</item>
                        <item name="externalProvider" xsi:type="string">myvendor_mymodule_myproductgrid.product_listing_data_source</item>
                        <item name="selectionsProvider" xsi:type="string">${ $.ns }.${ $.ns }.mymodule_mycategory_listing_columns.ids</item>
                        <item name="gridProvider" xsi:type="string">myvendor_mymodule_myproductgrid.myvendor_mymodule_myproductgrid</item>
                        <item name="addCategoryUrl" xsi:type="url" path="mymodule/product/assigncategory"/>
                    </item>
                </argument>
            </insertListing>
        </fieldset>
    </modal>
</listing>

Column JS assign.js:

define(
    [
        'Magento_Ui/js/grid/columns/actions',
        'jquery',
        'uiRegistry'
    ],
    function (Actions, $, registry) {
        'use strict';

        return Actions.extend({
            defaults: {
                bodyTmpl: 'My_Module/grid/cells/category/actions',
            },

            /**
             * Applies specified action.
             *
             * @param   {String} actionIndex - Actions' identifier.
             * @param   {Number} rowIndex - Index of a row.
             * @returns {ActionsColumn} Chainable.
             */
            applyAction: function (actionIndex, rowIndex) {
                var action = this.getAction(rowIndex, actionIndex),
                    callback = this._getCallback(action);
                if (action.modal) {
                    // Opening popup with category grid
                    var modal = registry.get('myvendor_mymodule_myproductgrid.myvendor_mymodule_myproductgrid.assign_category_modal');
                    modal.openModal();
                }
                return this;
            },
        });
    }
);

Template for Category Action Column:

<div if="$col.isSingle($row()._rowIndex)" style="min-width: 120px">
    <div style="float: left">
        <a
                repeat="foreach: $col.getVisibleActions($row()._rowIndex), item: '$action'"
                text="$action().value"
                attr="href: $action().url"
                target="_blank"
        />
    </div>
    <div style="float: right">
        <a
                class="action-menu-item"
                repeat="foreach: $col.getVisibleActions($row()._rowIndex), item: '$action'"
                click="$col.getActionHandler($action())"
                text="$action().label"
                attr="href: $action().href, 'class': $action().class, 'title':$action().label"/>
    </div>
</div>

<div if="$col.isMultiple($row()._rowIndex)" collapsible>
    <ul attr="'style': 'width:'+ ($col.getVisibleActions($row()._rowIndex).length * 30) + 'px'">
        <li class="mymodule actions-li" repeat="foreach: $col.getVisibleActions($row()._rowIndex), item: '$action'">
            <a click="$col.getActionHandler($action())"
               text="$action().label"
               attr="href: $action().href, 'data-action': 'item-' + $action().index, 'class': $action().class, 'title':$action().label, 'download':$action().download, 'disabled':$action().disabled"
            />
        </li>
    </ul>
</div>

<style>
    .mymodule.actions-li {
        list-style: none;
        display: inline;
    }

    .mymodule.actions {
        font-size: 0;
        cursor: pointer;
    }

    .mymodule.actions.edit:before {
        display: inline-block;
        content: "\270E";
        height:16px;
    }
</style>

Category Column PHP Component (Category.php):

namespace MyVendor\MyModule\Ui\Component\Listing\Columns\Product;

use Magento\Ui\Component\Listing\Columns\Column;

class Category extends Column
{
    /**
     * 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')] = [
                        'category' => [
                            // 'category_id' have the category id already assign
                            'modal' => ['category_id' => ""],
                            'label' => __('Assign Category'),
                            // 'category_value' have the category name already assign
                            'value' => $item['category_value'],
                            'class' => 'mymodule actions edit',
                            'url' => "",
                            'href' => ''
                        ]
                    ];
                }
            }
        }
        return $dataSource;
    }
}