How To Add Country And State Dropdown In Admin Side in Magento2
-
13-12-2019 - |
Question
I need to add country and state drop down in admin form how to do it
Solution
in admin form block in _prepareForm() add country and region
that is
in __construct() add country config source
protected $_countryFactory;
/**
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Framework\Registry $registry
* @param \Magento\Framework\Data\FormFactory $formFactory
* @param \Magento\Store\Model\System\Store $systemStore
* @param array $data
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\Data\FormFactory $formFactory,
\Magento\Store\Model\System\Store $systemStore,
\Magento\Cms\Model\Wysiwyg\Config $wysiwygConfig,
\Magento\Directory\Model\Config\Source\Country $countryFactory,
\Sugarcode\Test\Model\Status $status,
array $data = []
) {
$this->_systemStore = $systemStore;
$this->_wysiwygConfig = $wysiwygConfig;
$this->_status = $status;
$this->_countryFactory = $countryFactory;
parent::__construct($context, $registry, $formFactory, $data);
}
and in _prepareForm()
protected function _prepareForm()
{
.
.
.
.
.
old field
.
.
.
.
$optionsc=$this->_countryFactory->toOptionArray();
$country = $fieldset->addField(
'country_id',
'select',
[
'name' => 'country_id',
'label' => __('Country'),
'title' => __('Country'),
// 'onchange' => 'getstate(this)',
'values' => $optionsc,
]
);
//$optionsc=$this->_countryFactory->toOptionArray();
$fieldset->addField(
'region_id',
'select',
[
'name' => 'region_id',
'label' => __('Region'),
'title' => __('Region'),
'values' => ['--Please Select Country--'],
]
);
/*
* Add Ajax to the Country select box html output
*/
$country->setAfterElementHtml("
<script type=\"text/javascript\">
require([
'jquery',
'mage/template',
'jquery/ui',
'mage/translate'
],
function($, mageTemplate) {
$('#edit_form').on('change', '#country_id', function(event){
$.ajax({
url : '". $this->getUrl('test/*/regionlist') . "country/' + $('#country_id').val(),
type: 'get',
dataType: 'json',
showLoader:true,
success: function(data){
$('#region_id').empty();
$('#region_id').append(data.htmlconent);
}
});
})
}
);
</script>"
);
$form->setValues($model->getData());
$this->setForm($form);
return parent::_prepareForm();
}
and create admin side action file to get region that is app\code\Sugarcode\Test\Controller\Adminhtml\Lists\Regionlist.php
<?php
/**
*
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
// @codingStandardsIgnoreFile
namespace Sugarcode\Test\Controller\Adminhtml\Lists;
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Regionlist extends \Magento\Framework\App\Action\Action
{
/**
* @var \Magento\Framework\View\Result\PageFactory
*/
protected $resultPageFactory;
/**
* @var \Magento\Directory\Model\CountryFactory
*/
protected $_countryFactory;
/**
* @param \Magento\Framework\App\Action\Context $context
* @param \Magento\Framework\View\Result\PageFactory resultPageFactory
*/
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Directory\Model\CountryFactory $countryFactory,
\Magento\Framework\View\Result\PageFactory $resultPageFactory
)
{
$this->_countryFactory = $countryFactory;
$this->resultPageFactory = $resultPageFactory;
parent::__construct($context);
}
/**
* Default customer account page
*
* @return void
*/
public function execute()
{
$countrycode = $this->getRequest()->getParam('country');
$state = "<option value=''>--Please Select--</option>";
if ($countrycode != '') {
$statearray =$this->_countryFactory->create()->setId(
$countrycode
)->getLoadedRegionCollection()->toOptionArray();
foreach ($statearray as $_state) {
if($_state['value']){
$state .= "<option >" . $_state['label'] . "</option>";
}
}
}
$result['htmlconent']=$state;
$this->getResponse()->representJson(
$this->_objectManager->get('Magento\Framework\Json\Helper\Data')->jsonEncode($result)
);
}
}
once you change country region will load same way you can do for city also
If any one know better then this solution as like in we use in edit.phtml please share us
OTHER TIPS
In the block constructor, you'll need to enable two classes with the collection of regions and countries. Also, don't forget to add the corresponding fields in there.
Next, apply the standard RegionUpdater from lib/web/varien/form.js. it can be added in any convenient for you way - in our example we're using a child block with the template where it is called (just note that there're some required parameters: country elements, region (text), region (select) and the object that contains data for countries and regions (from the Helper directory).
In case you need to modify the list of countries and regions, do that not only in the form , but also in the data object from RegionUpdater.
Changes in the class of the form block, add new classes to di, the __construct method and make changes to the _prepareForm method.
<?php
/**
* @var \Magento\Directory\Model\Config\Source\Country
*/
protected $_country;
/**
* @var \Magento\Directory\Model\RegionFactory
*/
protected $_regionFactory;
// ... add them in __construct
// ...
// Add next changes in the _prepareForm method
$countries = $this->_country->toOptionArray(false, 'US');
$regionCollection = $this->_regionFactory->create()->getCollection()->addCountryFilter(
$formData['country_id']
);
$regions = $regionCollection->toOptionArray();
$fieldset->addField(
'country_id',
'select',
['name' => 'country_id', 'label' => __('Country'), 'required' => true, 'values' => $countries]
);
$fieldset->addField(
'region_id',
'select',
['name' => 'region_id', 'label' => __('State'), 'values' => $regions]
);
$fieldset->addField(
'region',
'text',
['name' => 'region', 'label' => __('Region')]
);
$fieldset->addField(
'city',
'text',
['name' => 'city', 'label' => __('City')]
);
$this->setChild(
'form_after',
$this->getLayout()->createBlock('Magento\Framework\View\Element\Template')->setTemplate('Vendor_Module::js.phtml')
);
?>
> Vendor_Module::js.phtml
<script>
require([
"jquery",
"mage/adminhtml/form"
], function ($) {
var updater = new RegionUpdater($('[name=country_id]')[0], $('[name=region]')[0], $('[name=region_id]')[0],
<?php echo $this->helper('Magento\Directory\Helper\Data')->getRegionJson() ?>,
'hide'
);
updater.disableRegionValidation();
window.updater = updater;
});
</script>
This is how it works:
1) by default
2) After you select the USD, the text field for the region is hidden (the 5th argument RegionUpdater constructor - this method will be applied to any inactive fields, also it can be hidden or disabled)
3) For Albania, there're no regions by default. Hence, we can see just the text field with hidden regions:
4) For Switzerland, we can see the regions again:
And it it goes without saying that you should make it convenient to use for your clients, as using the Hide method, the filed label is NOT hidden.
But upon the whole, RegionUpdater works well for a non-UI forms of Magento.
P.S. Also note that there's no way to add an updater for cities,as by default, Magento doesn't support the lists of Cities.
You can try using/replicationg the Config module's way.
Add the js.phtml block, that's also used in the shipping origin config, to your layout xml.
<referenceContainer name="js">
<block class="Magento\Backend\Block\Template" template="Magento_Config::system/config/js.phtml"/>
</referenceContainer>
Name your field ids as "country_id" and "region_id" and add "countries" css class to the country_id field.
$fieldset->addField(
'country_id',
'select',
[
'name' => 'country_id',
'label' => __('Country'),
'title' => __('Country'),
'values' => array_merge(['' => ''], $this->_countryOptions->toOptionArray()),
'class' => 'countries',
]
);
$fieldset->addField(
'region_id',
'text',
[
'name' => 'region_id',
'label' => __('Region/State'),
'title' => __('Region/State'),
]
);