2

I'm struggling to add a tab and a grid to magento's admin customer edit.

I can see how they are doing it with orders / invoices etc, but it goes against Magento's own best practices.

The goal : Create a new tab called 'Orders Two' and duplicate the customer order grid using UI components.

Current error is : Invalid method Vendor\Namespace\Block\Adminhtml\Customer\View\Tab\Orderstwo::isAjaxLoaded

But this is most likely just because of bad xml. I'm a bit lost

So far I have attempted to do it in the same way you create a tab and add a grid in the sales order view :

view/adminhtml/layout/customer_index_edit.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="customer_form">
            <block class="Module\Namespace\Block\Adminhtml\Customer\View\Tab\Orderstwo" name="customer_edit_tab_orderstwo">
                <action method="setTabLabel">
                    <argument name="label" xsi:type="string">Orders Two</argument>
                </action>
            </block>
        </referenceBlock>

        <referenceBlock name="customer_edit_tab_orderstwo">
            <uiComponent name="customer_view_orderstwo_grid"/>
        </referenceBlock>
    </body>
</page>

Block/Adminhtml/Customer/View/Tab/Orderstwo.php

<?php

namespace Module\Namespace\Block\Adminhtml\Customer\View\Tab;

use Magento\Framework\View\Element\Context;
use Magento\Customer\Controller\RegistryConstants;
use Magento\Framework\Registry;
use Magento\Framework\AuthorizationInterface;
use Magento\Framework\View\Element\Text\ListText;
use Magento\Backend\Block\Widget\Tab\TabInterface;

class Orderstwo extends ListText implements TabInterface
{
    /**
     * Core registry
     *
     * @var Registry
     */
    protected $_coreRegistry = null;

    /**
     * @var bool
     */
    protected $isAjaxLoaded = true;

    /**
     * Orderstwo constructor.
     *
     * @param Context                $context
     * @param AuthorizationInterface $authorization
     * @param Registry               $registry
     * @param array                  $data
     */
    public function __construct(
        Context $context,
        AuthorizationInterface $authorization,
        Registry $registry,
        array $data = []
    ) {
        $this->_authorization = $authorization;
        $this->_coreRegistry = $registry;
        parent::__construct($context, $data);
    }

    /**
     * @inheritdoc
     */
    public function canShowTab()
    {
        return true;
    }


    /**
     * {@inheritdoc}
     */
    public function getTabLabel()
    {
        return __('Orders Two');
    }

    /**
     * {@inheritdoc}
     */
    public function getTabTitle()
    {
        return __('Orders Two');
    }


    /**
     * {@inheritdoc}
     */
    public function isHidden()
    {
        return false;
    }
}

My UI component xml isn't really relevant because it's not even being loaded at the moment.

<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<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">customer_view_orderstwo_grid.sales_order_view_orderstwo_grid_data_source</item>
            <item name="deps" xsi:type="string">customer_view_orderstwo_grid.sales_order_view_orderstwo_grid_data_source</item>
        </item>
        <item name="spinner" xsi:type="string">customer_view_orderstwo_grid_columns</item>
    </argument>
    <dataSource name="sales_order_view_orderstwo_grid_data_source">
        <argument name="dataProvider" xsi:type="configurableObject">
            <argument name="class" xsi:type="string">Vendor\Namespace\Ui\DataProvider\Customer\View\Orderstwo\Grid\DataProvider</argument>
            <argument name="name" xsi:type="string">sales_order_view_orderstwo_grid_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="update_url" xsi:type="url" path="mui/index/render"/>
                    <item name="storageConfig" xsi:type="array">
                        <item name="indexField" xsi:type="string">entity_id</item>
                    </item>
                </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/grid/provider</item>
            </item>
        </argument>
    </dataSource>
    <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>
        <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="mui/bookmark/save"/>
                        <item name="deleteUrl" xsi:type="url" path="mui/bookmark/delete"/>
                        <item name="namespace" xsi:type="string">customer_view_orderstwo_grid</item>
                    </item>
                </item>
            </argument>
        </bookmark>
        <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">customer_view_orderstwo_grid.customer_view_orderstwo_grid.customer_view_orderstwo_grid_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>
        <filters name="listing_filters">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="displayArea" xsi:type="string">dataGridFilters</item>
                    <item name="dataScope" xsi:type="string">filters</item>
                    <item name="storageConfig" xsi:type="array">
                        <item name="provider" xsi:type="string">
                            customer_view_orderstwo_grid.customer_view_orderstwo_grid.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">
                            customer_view_orderstwo_grid.customer_view_orderstwo_grid.listing_top.listing_filters
                        </item>
                        <item name="imports" xsi:type="array">
                            <item name="visible" xsi:type="string">
                                customer_view_orderstwo_grid.customer_view_orderstwo_grid.listing_top.bookmarks:current.columns.${ $.index }.visible
                            </item>
                        </item>
                    </item -->
                </item>
            </argument>
            <filterRange name="entity_id">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="dataScope" xsi:type="string">entity_id</item>
                        <item name="label" xsi:type="string" translate="true">ID</item>
                        <item name="childDefaults" xsi:type="array">
                            <item name="provider" xsi:type="string">
                                customer_view_orderstwo_grid.customer_view_orderstwo_grid.listing_top.listing_filters
                            </item>
                        </item>
                    </item>
                </argument>
                <filterInput name="from">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="dataScope" xsi:type="string">from</item>
                            <item name="label" xsi:type="string" translate="true">from</item>
                            <item name="placeholder" xsi:type="string" translate="true">From</item>
                        </item>
                    </argument>
                </filterInput>
                <filterInput name="to">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="dataScope" xsi:type="string">to</item>
                            <item name="label" xsi:type="string" translate="true">to</item>
                            <item name="placeholder" xsi:type="string" translate="true">To</item>
                        </item>
                    </argument>
                </filterInput>
            </filterRange>
            <filterRange name="update_time" class="Magento\Ui\Component\Filters\Type\DateRange">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="dataScope" xsi:type="string">created_at</item>
                        <item name="label" xsi:type="string" translate="true">Released Date</item>
                        <item name="childDefaults" xsi:type="array">
                            <item name="provider" xsi:type="string">
                                gene_productqa_answer_listing.gene_productqa_answer_listing.listing_top.listing_filters
                            </item>
                        </item>
                    </item>
                </argument>
                <filterDate name="from">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="dataScope" xsi:type="string">from</item>
                            <item name="label" xsi:type="string" translate="true">from</item>
                            <item name="placeholder" xsi:type="string" translate="true">From</item>
                            <item name="dateFormat" xsi:type="string" translate="true">MM/dd/YYYY</item>
                        </item>
                    </argument>
                </filterDate>
                <filterDate name="to">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="dataScope" xsi:type="string">to</item>
                            <item name="label" xsi:type="string" translate="true">to</item>
                            <item name="placeholder" xsi:type="string" translate="true">To</item>
                            <item name="dateFormat" xsi:type="string" translate="true">MM/dd/YYYY</item>
                        </item>
                    </argument>
                </filterDate>
            </filterRange>
        </filters>
        <massaction name="listing_massaction" />

        <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">
                            customer_view_orderstwo_grid.customer_view_orderstwo_grid.listing_top.bookmarks
                        </item>
                        <item name="namespace" xsi:type="string">current.paging</item>
                    </item>
                    <item name="selectProvider" xsi:type="string">
                        customer_view_orderstwo_grid.customer_view_orderstwo_grid.customer_view_orderstwo_grid_columns.ids
                    </item>
                    <item name="displayArea" xsi:type="string">bottom</item>
                    <item name="options" xsi:type="array">
                        <item name="20" xsi:type="array">
                            <item name="value" xsi:type="number">20</item>
                            <item name="label" xsi:type="string" translate="true">20</item>
                        </item>
                        <item name="30" xsi:type="array">
                            <item name="value" xsi:type="number">30</item>
                            <item name="label" xsi:type="string" translate="true">30</item>
                        </item>
                        <item name="50" xsi:type="array">
                            <item name="value" xsi:type="number">50</item>
                            <item name="label" xsi:type="string" translate="true">50</item>
                        </item>
                        <item name="100" xsi:type="array">
                            <item name="value" xsi:type="number">100</item>
                            <item name="label" xsi:type="string" translate="true">100</item>
                        </item>
                        <item name="200" xsi:type="array">
                            <item name="value" xsi:type="number">200</item>
                            <item name="label" xsi:type="string" translate="true">200</item>
                        </item>
                    </item>
                </item>
            </argument>
        </paging>
    </container>
    <columns name="customer_view_orderstwo_grid_columns">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="storageConfig" xsi:type="array">
                    <item name="provider" xsi:type="string">customer_view_orderstwo_grid.customer_view_orderstwo_grid.listing_top.bookmarks
                    </item>
                    <item name="namespace" xsi:type="string">current</item>
                </item>
                <item name="childDefaults" xsi:type="array">
                    <item name="fieldAction" xsi:type="array">
                        <item name="provider" xsi:type="string">
                            customer_view_orderstwo_grid.customer_view_orderstwo_grid.customer_view_orderstwo_grid_columns.actions
                        </item>
                        <item name="target" xsi:type="string">applyAction</item>
                        <item name="params" xsi:type="array">
                            <item name="0" xsi:type="string">edit</item>
                            <item name="1" xsi:type="string">${ $.$data.rowIndex }</item>
                        </item>
                    </item>
                    <item name="controlVisibility" xsi:type="boolean">true</item>
                    <item name="storageConfig" xsi:type="array">
                        <item name="provider" xsi:type="string">
                            customer_view_orderstwo_grid.customer_view_orderstwo_grid.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">
                    <item name="resizeEnabled" xsi:type="boolean">false</item>
                    <item name="resizeDefaultWidth" xsi:type="string">55</item>
                    <item name="indexField" xsi:type="string">entity_id</item>
                </item>
            </argument>
        </selectionsColumn>
        <column name="entity_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>

    </columns>
</listing>

2 Answers 2

2

I'm going to answer my own question here. After a lot of digging through core... The Magento_Customer module is just not built properly yet. Unlike the sales order view the customer view does not render the grids on the page using knockout but rather makes separate ajax request when you select the different tabs. For now I think you just need to do it the M1 way by defining your fields etc in a block class and rendering that out to html.

Eventually however, i'm sure Magento will get around to adhering to their own standards and it'll stop working. So just be ready for that. Here's a tutorial for doing it the wrong way : http://www.ibnab.com/en/blog/magento-2/magento-2-backend-create-custom-tab-in-customer-view-and-load-grid-inside-admin

4
  • HI @Franks how to save product grid checkbox checked data Nov 15, 2016 at 5:54
  • You didn't even use the UI component to built the grid. The question completely irrelevant to your answer Jan 20, 2020 at 4:34
  • @SyedSaleem as stated in my answer at the time of writing the post (3 years 5 months ago) it was not possible to use the UI component as it didn't exist. Maybe Magento now has the proper UI component. I wouldn't know, I don't use it anymore. Your comment however, isn't very helpful to anyone. During the time, i'm sure this would have helped a lot of people!
    – Frank
    Jan 22, 2020 at 14:45
0

I have tried to add a tab with a Form UiComponent to the Sales - Order - View page the same way as you, but have the same problem, it doesn't show.

This is my code:

view/adminhtml/layout/sales_order_view.xml

<?xml version="1.0" ?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="sales_order_tabs">
            <block class="Vendor\ModuleName\Block\Adminhtml\Order\View\Tab\Expedition" name="sales_order_expedition.form.container" />
            <action method="addTab">
                <argument name="name" xsi:type="string">order_expedition</argument>
                <argument name="block" xsi:type="string">sales_order_expedition.form.container</argument>
            </action>
        </referenceBlock>
        <referenceBlock name="sales_order_expedition.form.container">
            <uiComponent name="sales_order_view_expedition_form"/>
        </referenceBlock>
    </body>
</page>

Block/Adminhtml/Order/View/Tab/Expedition.php

<?php

namespace Vendor\ModuleName\Block\Adminhtml\Order\View\Tab;


use \Magento\Backend\Block\Widget\Tab\TabInterface;
use \Magento\Framework\View\Element\Template;


class Expedition extends Template implements TabInterface {

    /**
     * {@inheritdoc}
     */
    public function getTabLabel() {
        return 'Expedition';
    }

    /**
     * {@inheritdoc}
     */
    public function getTabTitle() {
        return 'Expedition';
    }

    /**
     * {@inheritdoc}
     */
    public function canShowTab() {
        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function isHidden() {
        return false;
    }
}

If I add the uiComponent item to a Magento core block like sales_order_invoice.grid.container, it shows the form. Code:

    <referenceBlock name="sales_order_invoice.grid.container">
        <uiComponent name="sales_order_view_expedition_form"/>
    </referenceBlock>

Did you find the way to add the uiComponent item to a custom tab?

1
  • Hi Ivan, I am facing the same issue. Did you find any solution? Jul 5, 2019 at 11:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.