Magento 2 comes with many technique already exist in version 1 but with new way for implementing , one of this flexible tables (grids) in the system configuration.
you can download the project of course from github
We imagine you have created module , we started from system.xml inside Ibnab/Table/etc/adminhtml/system.xml
1 – Create the field :
for more infos about how working with system.xml plz visit our tutorial :
so we need add this part of code inside system.xml :
<field id="active" translate="label" sortOrder="220" showInDefault="1" showInWebsite="1" showInStore="0"> <label>active buy</label> <frontend_model>Ibnab\Table\Block\System\Config\Form\Field\Active</frontend_model> <backend_model>Magento\Config\Model\Config\Backend\Serialized\ArraySerialized</backend_model> </field>
frontend_model : block responsible of rendering the columns content of table
backend_model : it used for saving and loading data from db as serialized format , use can use the standard Magento\Config\Model\Config\Backend\Serialized\ArraySerialized , or create your own like : Magento\Braintree\Model\System\Config\Backend\Countrycreditcard
2 – Create frontend model :
we need create our class inside Ibnab/Table/Block/System/Form/Field folder , ok here create block Active.php and fill with :
</p> <p><?php /** * Grid columns * * @var array */ protected $_columns = []; protected $_customerGroupRenderer; /** * Enable the "Add after" button or not * * @var bool */ protected $_addAfter = true; /** * Label of add button * * @var string */ protected $_addButtonLabel; /** * Check if columns are defined, set template * * @return void */ protected function _construct() { parent::_construct(); $this->_addButtonLabel = __('Add'); } /** * Returns renderer for country element * * @return \Magento\Braintree\Block\Adminhtml\Form\Field\Countries */ protected function getCustomerGroupRenderer() { if (!$this->_customerGroupRenderer) { $this->_customerGroupRenderer = $this->getLayout()->createBlock( '\Ibnab\Table\Block\Adminhtml\Form\Field\CustomerGroup', '', ['data' => ['is_render_to_js_template' => true]] ); } return $this->_customerGroupRenderer; } /** * Prepare to render * * @return void */ protected function _prepareToRender() { $this->addColumn( 'customer_group', [ 'label' => __('Customer Group'), 'renderer' => $this->getCustomerGroupRenderer(), ] ); $this->_addAfter = false; $this->_addButtonLabel = __('Add'); } protected function _prepareArrayRow(\Magento\Framework\DataObject $row) { $customerGroup = $row->getCustomerGroup(); $options = []; if ($customerGroup) { $options['option_' . $this->getCustomerGroupRenderer()->calcOptionHash($customerGroup)] = 'selected="selected"'; } $row->setData('option_extra_attrs', $options); } /** * Render array cell for prototypeJS template * * @param string $columnName * @return string * @throws \Exception */ public function renderCellTemplate($columnName) { if ($columnName == "active") { $this->_columns[$columnName]['class'] = 'input-text required-entry validate-number'; $this->_columns[$columnName]['style'] = 'width:50px'; } return parent::renderCellTemplate($columnName); } }
Our class extend the \Magento\Config\Block\System\Config\Form\Field\FieldArray\AbstractFieldArray yes we need table field .
We have here many important functions (1 function here need override the parent function for declaring your custom column _prepareToRender() ):
protected function _prepareToRender() { $this->addColumn( 'customer_group', [ 'label' => __('Customer Group'), 'renderer' => $this->getCustomerGroupRenderer(), ] ); $this->_addAfter = false; $this->_addButtonLabel = __('Add'); }
here we decalre our custom column “input field” the first is select field we related to custom renderer with function getCustomerGroupRenderer() (we back to it)
and the default input text :
we use the function of parent :
public function addColumn($name, $params) { $this->_columns[$name] = [ 'label' => $this->_getParam($params, 'label', 'Column'), 'size' => $this->_getParam($params, 'size', false), 'style' => $this->_getParam($params, 'style'), 'class' => $this->_getParam($params, 'class'), 'renderer' => false, ]; if (!empty($params['renderer']) && $params['renderer'] instanceof \Magento\Framework\View\Element\AbstractBlock) { $this->_columns[$name]['renderer'] = $params['renderer']; } }
the parent function find if have a custom renderer it use , if not it use the default input text field like our case active field .
We back to our renderer for our first column declaration :
$this->addColumn( 'customer_group', [ 'label' => __('Customer Group'), 'renderer' => $this->getCustomerGroupRenderer(), ] );
the function is :
protected function getCustomerGroupRenderer() { if (!$this->_paymentMethodRenderer) { $this->_paymentMethodRenderer = $this->getLayout()->createBlock( '\Ibnab\Table\Block\Adminhtml\Form\Field\CustomerGroup', '', ['data' => ['is_render_to_js_template' => true]] ); } return $this->_paymentMethodRenderer; }
Yes we use custom block for showing our field (\Ibnab\Table\Block\Adminhtml\Form\Field\CustomerGroup) the content is :
<?php</p> <p>/** * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ namespace Ibnab\Table\Block\Adminhtml\Form\Field; class CustomerGroup extends \Magento\Framework\View\Element\Html\Select { /** * methodList * * @var array */ protected $groupfactory; /** * Constructor * * @param \Magento\Framework\View\Element\Context $context * @param \Magento\Braintree\Model\System\Config\Source\Country $countrySource * @param \Magento\Directory\Model\ResourceModel\Country\CollectionFactory $countryCollectionFactory * @param array $data */ public function __construct( \Magento\Framework\View\Element\Context $context, \Magento\Customer\Model\GroupFactory $groupfactory, array $data = [] ) { parent::__construct($context, $data); $this->groupfactory = $groupfactory; } /** * Returns countries array * * @return array */ /** * Render block HTML * * @return string */ public function _toHtml() { if (!$this->getOptions()) { $customerGroupCollection = $this->groupfactory->create()->getCollection(); foreach ($customerGroupCollection as $customerGroup) { $this->addOption($customerGroup->getCustomerGroupId(), $customerGroup->getCustomerGroupCode()); } } return parent::_toHtml(); } /** * Sets name for input element * * @param string $value * @return $this */ public function setInputName($value) { return $this->setName($value); } }
Our block extend \Magento\Framework\View\Element\Html\Select , we want select field element ,
in construct we inject the customer group factory and used inside public function _toHtml() for filled the select input box :
public function _toHtml() { if (!$this->getOptions()) { $customerGroupCollection = $this->groupfactory->create()->getCollection(); foreach ($customerGroupCollection as $customerGroup) { $this->addOption($customerGroup->getCustomerGroupId(), $customerGroup->getCustomerGroupCode()); } } return parent::_toHtml(); }
re back to our array table and explore function :
protected function _prepareArrayRow(\Magento\Framework\DataObject $row) { $customerGroup = $row->getCustomerGroup(); $options = []; if ($paymentMethod) { $options['option_' . $this->getCustomerGroupRenderer()->calcOptionHash($customerGroup)] = 'selected="selected"'; } $row->setData('option_extra_attrs', $options); }</p> <p>}
we use for select current selected option in our select field element .
3 – Add validation :
you can add validation before save the serialized value , add function :
/** * Render array cell for prototypeJS template * * @param string $columnName * @return string * @throws \Exception */ public function renderCellTemplate($columnName) { if ($columnName == "active") { $this->_columns[$columnName]['class'] = 'input-text required-entry validate-number'; $this->_columns[$columnName]['style'] = 'width:50px'; } return parent::renderCellTemplate($columnName); }
here we validate the active field is required and number type .
4 – How using the configuration value :
first inject the $scopeConfig inside the class where you want use the configuration :
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
$tableConfig = $this->scopeConfig->getValue('ibnab_activebuy_config/general/active', ScopeConfigInterface::SCOPE_TYPE_DEFAULT); if ($tableConfig) : foreach($tableConfigResults as $tableConfigResult) { $customer_group = $tableConfigResult['customer_group']; $active = $tableConfigResult['active']; } endif; }
that is all
Comments