Magento – magento 2 adding tab in custom module edit section

adminhtmlgrid layoutmagento-2.1.9magento2

I want to create a tab custom module admin section I have set the layout and also created the tab page but the layout is not coming as expected it to be.The tab comes on the left side under the tab heading which is wrong(please check image for reference).Any help on this, thanks in advance.enter image description here

the layout file is company_grid_edit.xml

<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">
<update handle="editor"/>
<body>
    <referenceContainer name="content">
        <block class="My\Company\Block\Adminhtml\Template\Edit" name="my_company_template_edit"/>
    </referenceContainer>
    <referenceContainer name="left">
        <block class="My\Company\Block\Adminhtml\Template\Edit\Tabs" name="template_edit_tabs">
        <block class="My\Company\Block\Adminhtml\Template\Edit\Tab\Main" name="template_edit_tab_main"/>

            <action method="addTab">
                <argument name="name" xsi:type="string">main_section</argument>
                <argument name="block" xsi:type="string">template_edit_tab_main</argument>
            </action>
        </block>
    </referenceContainer>
</body>

Main.php

 <?php
namespace My\Company\Block\Adminhtml\Template\Edit\Tab;

class Main extends \Magento\Backend\Block\Widget\Form\Generic implements \Magento\Backend\Block\Widget\Tab\TabInterface
{  
    protected $_systemStore;

    public function __construct(
        \Magento\Backend\Block\Template\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\Data\FormFactory $formFactory,
        \Magento\Store\Model\System\Store $systemStore,
        array $data = []
    ) {
        $this->_systemStore = $systemStore;
        parent::__construct($context, $registry, $formFactory, $data);
    }


    protected function _prepareForm()
    {

        $model = $this->_coreRegistry->registry('_gridpart2_template');

        if ($this->_isAllowedAction('My_Company::save')) {
            $isElementDisabled = false;
        } else {
            $isElementDisabled = true;
        }

        $form = $this->_formFactory->create();

        $form->setHtmlIdPrefix('news_main_');

        $fieldset = $form->addFieldset('base_fieldset', ['legend' => __('Comapny Information')]);

        if ($model->getId()) {
            $fieldset->addField('id', 'hidden', ['name' => 'id']);
        }

        $fieldset->addField(
            'company_name',
            'text',
            [
                'name' => 'company_name',
                'label' => __('Company Name'),
                'title' => __('Company Name'),
                'required' => true,
                'disabled' => $isElementDisabled
            ]
        );

        $fieldset->addField(
            'company_email',
            'text',
            [
                'name' => 'company_email',
                'label' => __('Company Email'),
                'title' => __('Company Email'),
                'required' => true,
                'disabled' => $isElementDisabled
            ]
        );

        $fieldset->addField(
            'legal_name',
            'text',
            [
                'name' => 'legal_name',
                'label' => __('Comapny Legal Name'),
                'title' => __('Comapny Legal Name'),
                'required' => true,
                'disabled' => $isElementDisabled
            ]
        );

        $fieldset->addField(
            'vat_number',
            'text',
            [
                'name' => 'vat_number',
                'label' => __('Vat Number'),
                'title' => __('Vat Number'),
                'required' => true,
                'disabled' => $isElementDisabled
            ]
        );

        $fieldset->addField(
            'address_line1',
            'text',
            [
                'name' => 'address_line1',
                'label' => __('Address Line'),
                'title' => __('Address Line'),
                'required' => true,
                'disabled' => $isElementDisabled
            ]
        );

        $fieldset->addField(
            'state',
            'text',
            [
                'name' => 'state',
                'label' => __('State'),
                'title' => __('State'),
                'required' => true,
                'disabled' => $isElementDisabled
            ]
        );
        $fieldset->addField(
            'country',
            'text',
            [
                'name' => 'country',
                'label' => __('Country'),
                'title' => __('Country'),
                'required' => true,
                'disabled' => $isElementDisabled
            ]
        );

         $fieldset->addField(
            'phone_number',
            'text',
            [
                'name' => 'phone_number',
                'label' => __('Phone Number'),
                'title' => __('Phone Number'),
                'required' => true,
                'disabled' => $isElementDisabled
            ]
        );  

        $this->_eventManager->dispatch('adminhtml_company_edit_tab_main_prepare_form', ['form' => $form]);

        $form->setValues($model->getData());
        $this->setForm($form);

        return parent::_prepareForm();
    }


    public function getTabLabel()
    {
        return __('Company Information');
    }


    public function getTabTitle()
    {
        return __('Company Information');
    }


    public function canShowTab()
    {
        return true;
    }

    public function isHidden()
    {
        return false;
    }


    protected function _isAllowedAction($resourceId)
    {
        return $this->_authorization->isAllowed($resourceId);
    }
}

Tabs.php

<?php
namespace My\Company\Block\Adminhtml\Template\Edit;

class Tabs extends \Magento\Backend\Block\Widget\Tabs
{

    public function __construct(\Magento\Backend\Block\Template\Context $context, \Magento\Framework\Json\EncoderInterface $jsonEncoder, \Magento\Backend\Model\Auth\Session $authSession, array $data = array()) {

        parent::__construct($context, $jsonEncoder, $authSession, $data);
    }

    protected function _construct()
    {

        parent::_construct();
        $this->setId('page_tabs');
        $this->setDestElementId('edit_form');
        $this->setTitle(__('Company Information'));
    }
}

Edit.php in My\Company\Block\Adminhtml\Template

<?php
namespace My\Company\Block\Adminhtml\Template;

class Edit extends \Magento\Backend\Block\Template {


    protected $_coreRegistry = null;

    public function __construct(
    \Magento\Backend\Block\Template\Context $context, \Magento\Framework\Registry $registry, array $data = []
    ) {
        $this->_coreRegistry = $registry;
        parent::__construct($context, $data);
    }


    public function getModel() {
        return $this->_coreRegistry->registry('_gridpart2_template');
    }


    protected function _prepareLayout() {
        $this->getToolbar()->addChild(
                'back_button', 'Magento\Backend\Block\Widget\Button', [
            'label' => __('Back'),
            'onclick' => "window.location.href = '" . $this->getUrl('*/*') . "'",
            'class' => 'action-back'
                ]
        );

        $this->getToolbar()->addChild(
                'reset_button', 'Magento\Backend\Block\Widget\Button', [
            'label' => __('Reset'),
            'onclick' => 'window.location.href = window.location.href',
            'class' => 'reset'
                ]
        );

        if ($this->getRequest()->getParam('id', false)) {
            $this->getToolbar()->addChild(
                    'delete_button', 'Magento\Backend\Block\Widget\Button', [
                'label' => __('Delete'),
                'data_attribute' => [
                    'role' => 'template-delete',
                ],
                'class' => 'delete'
                    ]
            );
        }

        $this->getToolbar()->addChild(
                'save_button', 'Magento\Backend\Block\Widget\Button', [
            'label' => __('Save'),
            'data_attribute' => [
                'role' => 'template-save',
            ],
            'class' => 'save primary',
            'onclick' => 'window.location.href = window.location.href',
                ]
        );


        return parent::_prepareLayout();
    }


    public function getEditMode() {

        if ($this->getModel()->getId()) {
            return true;
        }
        return false;
    }

    public function getHeaderText() {
        if ($this->getRequest()->getParam('id', false)) {
            return __('Edit  ');
        }

        return __('New  ');
    }


    public function getForm() {
        return $this->getLayout()->createBlock('My\Company\Block\Adminhtml\Template\Edit\Form')->toHtml();
    }


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

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


    public function getSaveAsFlag() {
        return $this->getRequest()->getParam('_save_as_flag') ? '1' : '';
    }


    protected function isSingleStoreMode() {
        return $this->_storeManager->isSingleStoreMode();
    }


    protected function getStoreId() {
        return $this->_storeManager->getStore(true)->getId();
    }

}

Best Answer

I was having the same issue like the content was showing just below the tab name.

enter image description here

Creating Form.php inside Vendor/Module/Block/Adminhtml/Faq/Edit/Form.php helped me solved my issue. after creating Form.php:

enter image description here

enter image description here


Here's a complete structure which I followed:

  1. Admin layout xml file:

    <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    layout="admin-2columns-left" xsi:noNamespaceSchemaLocation="../../../../../../
    ../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">
        <body>
            <referenceContainer name="left">
                <block class="Invigorate\ProductQuestions\Block\Adminhtml\Faq\Edit\Tabs"
                    name="invigorate_productquestions_faq.edit.tabs"/>
            </referenceContainer>
            <referenceContainer name="content">
                <block class="Invigorate\ProductQuestions\Block\Adminhtml\Faq\Edit"
                    name="invigorate_productquestions_faq.edit"/>
            </referenceContainer>
        </body>
    </page>
    
  2. Now create Vendor/Module/Block/Adminhtml/Faq/Edit/Tabs.php

    <?php
    
    namespace Invigorate\ProductQuestions\Block\Adminhtml\Faq\Edit;
    
    use Magento\Backend\Block\Widget\Tabs as WidgetTabs;
    
    class Tabs extends WidgetTabs
    {
        protected function _construct()
        {
            parent::_construct();
            $this->setId('faq_edit_tabs');
            $this->setDestElementId('edit_form');
            $this->setTitle(__('FAQ Information'));
        }
        protected function _beforeToHtml()
        {
            $this->addTab(
                'faq_info',
                [
                    'label' => __('Editing Record'),
                    'title' => __('Editing Record'),
                    'content' => 'Editing record fields',//Change this to your block layout as per your need.
                    'active' => true
                ]
            );
            $this->addTab(
                'faq_products',
                [
                    'label' => __('Products'),
                    'title' => __('Products'),
                    'content' => 'Products Block',//Change this to your block layout as per your need.
                    'active' => false
                ]
            );
            return parent::_beforeToHtml();
        }
    }
    
  3. Vendor/Module/Block/Adminhtml/Faq/Edit.php

    <?php
    namespace Invigorate\ProductQuestions\Block\Adminhtml\Faq;
    use Magento\Backend\Block\Widget\Form\Container;
    use Magento\Backend\Block\Widget\Context;
    use Magento\Framework\Registry;
    
    class Edit extends Container
    {
        protected $_coreRegistry = null;
        public function __construct(
            Context $context,
            Registry $registry,
            array $data = []
        ) {
            $this->_coreRegistry = $registry;
            parent::__construct($context, $data);
        }
        protected function _construct()
        {
            $this->_objectId = 'id';
            $this->_controller = 'adminhtml_faq';
            $this->_blockGroup = 'Invigorate_ProductQuestions';
    
            parent::_construct();
        }
        protected function _prepareLayout()
        {
            $this->_formScripts[] = "
                function toggleEditor() {
                    if (tinyMCE.getInstanceById('post_content') == null) {
                        tinyMCE.execCommand('mceAddControl', false, 'post_content');
                    } else {
                        tinyMCE.execCommand('mceRemoveControl', false, 'post_content');
                    }
                };
            ";
            return parent::_prepareLayout();
        }
    }
    
  4. Now create Form.php inside Vendor/Module/Block/Adminhtml/Faq/Edit/Form.php

    <?php
    namespace Invigorate\ProductQuestions\Block\Adminhtml\Faq\Edit;
    use Magento\Backend\Block\Widget\Form\Generic;
    class Form extends Generic
    {
        protected function _prepareForm()
        {
            $form = $this->_formFactory->create(
                [
                    'data' => [
                        'id'    => 'edit_form',
                        'action' => $this->getData('action'),
                        'method' => 'post'
                    ]
                ]
            );
            $form->setUseContainer(true);
            $this->setForm($form);
            return parent::_prepareForm();
        }
    }
    

Note: Please change Vendor, Module and other necessary names as per your need and you're good to go. and inside Tabs.php inside Tab content mentioned your block and replace static content string.

I hope this will help you, Thank you :)