Как вставить сетку с несколькими столбцами в форму администратора?
Мне нужно вставить сетку в форму администратора, содержащую два столбца, и в каждой строке должна быть кнопка удаления. Есть ли способ достичь этого
2 answers
Тебе нужна пара вещей. Прежде всего, рядом с обычным table
, который вы создадите для своего модуля, в котором хранятся данные формы adminhtml
, вам понадобится второй table
, в котором хранятся данные URL-адресов с полями
- идентификатор сущности
- идентификатор родителя
- метка
- url-адрес
- сортировщик
Создайте соответствующие модели ресурсов.
Рендеринг в Adminhtml
Добавление нового средства визуализации в генератор форм. Я только что добавил поле, в котором будет отображаться средство визуализации
app/code/[codepool]/Namespace/Module/BLock/Adminhtml/[Module]/Edit/Tab/General.php
class [Namespace]_[Module]_Block_Adminhtml_[Module]_Edit_Tab_General extends Mage_Adminhtml_Block_Widget_Form
{
protected function _prepareForm()
{
$form = new Varien_Data_Form();
$this->setForm($form);
$fieldset = $form->addFieldset('[module]_form', array('legend'=>Mage::helper('[namespace]_[module]')->__('General')));
[...]
$urlsField = $fieldset->addField('urls', 'text', array(
'name' => 'urls',
'label' => Mage::helper('[namespace]_[module]')->__('URLS'),
'required' => false,
));
$urlsField = $form->getElement('urls');
$urlsField->setRenderer(
$this->getLayout()->createBlock('[namespace]_[module]/adminhtml_[module]_edit_renderer_urls')
);
[...]
}
}
Класс визуализации, который добавляет шаблон phtml
app/code/[codepool]/Namespace/Module/BLock/Adminhtml/[Module]/Edit/Renderer/Urls.php
class [Namespace]_[Module]_Block_Adminhtml_[Module]_Edit_Renderer_Urls
extends Mage_Adminhtml_Block_Widget
implements Varien_Data_Form_Element_Renderer_Interface
{
/**
* Initialize block
*/
public function __construct()
{
$this->setTemplate('[namespace]_[module]/urls.phtml');
}
/**
* Render HTML
*
* @param Varien_Data_Form_Element_Abstract $element
* @return string
*/
public function render(Varien_Data_Form_Element_Abstract $element)
{
$this->setElement($element);
return $this->toHtml();
}
}
И шаблон, который отображает заполненные параметры и добавляет шаблон javascript для других строк.
app/design/adminhtml/default/default/template/[namespace]_[module]/urls.phtml
$_htmlId = $this->getElement()->getHtmlId();
$_htmlClass = $this->getElement()->getClass();
$_htmlName = $this->getElement()->getName();
$_readonly = $this->getElement()->getReadonly();
$collection = Mage::registry('[namespace]_[module]_data')->getUrls(); // this gets the URLs from the model that is loaded for this item, so the class [Namespace]_[Module]_Model_[Object] needs a method `getUrls`
$_counter = 0;
?>
<tr>
<td class="label"><?php echo $this->getElement()->getLabel() ?></td>
<td colspan="10" class="grid hours">
<table id="attribute-options-table" class="data border [module]-urls" cellspacing="0" cellpadding="0"><tbody>
<tr class="headings">
<th><?php echo $this->__('Label') ?></th>
<th><?php echo $this->__('Url') ?></th>
<th class="last"><button id="add_new_option_button" title="Add Option" type="button" class="scalable add"><span><span><span><?php echo $this->__('Add Option') ?></span></span></span></button></th>
</tr>
<?php foreach ($collection as $_item): ?>
<tr class="option-row [module]-urls-row" id="urls-row-<?php echo $_counter?>">
<td><input name="<?php echo $_htmlName; ?>[value][option_<?php echo $_counter ?>][label]" value="<?php echo $_item->getLabel() ?>" class="input-text" type="text"></td>
<td><input name="<?php echo $_htmlName; ?>[value][option_<?php echo $_counter ?>][url]" value="<?php echo $_item->getUrl() ?>" class="input-text" type="text"></td>
<td class="a-left" id="delete_button_container_option_<?php echo $_counter ?>'">
<input name="<?php echo $_htmlName; ?>[value][option_<?php echo $_counter ?>][id]" value="<?php echo $_item->getId() ?>" type="hidden">
<input id="delete-row-<?php echo $_counter ?>" type="hidden" class="delete-flag" name="<?php echo $_htmlName; ?>[delete][option_<?php echo $_counter ?>]" value=""/>
<button onclick="$('hour-row-<?php echo $_counter ?>').style.display='none'; $('delete-row-<?php echo $_counter ?>').setValue(1);" title="Delete" type="button" class="scalable delete delete-option"><span><span><span>Delete</span></span></span></button>
</td>
</tr>
<?php
$_counter++;
endforeach;
?>
</tbody></table>
<script type="text/javascript">//<![CDATA[
var _form_html_row = '<tr class="option-row [module]-urls-row" id="urls-row-{{id}}"><td><input name="<?php echo $_htmlName; ?>[value][option_{{id}}][label]" value="" class="input-text" type="text"></td><td><input name="<?php echo $_htmlName; ?>[value][option_{{id}}][url]" value="" class="input-text" type="text"></td><td class="a-left" id="delete_button_container_option_{{id}}"><input name="<?php echo $_htmlName; ?>[value][option_{{id}}][id]" value="" type="hidden"><input id="delete-row-{{id}}" type="hidden" class="delete-flag" name="<?php echo $_htmlName; ?>[delete][option_{{id}}]" value=""/><button onclick="$(\'urls-row-{{id}}\').style.display=\'none\'; $(\'delete-row-{{id}}\').setValue(1);" title="Delete" type="button" class="scalable delete delete-option"><span><span><span>Delete</span></span></span></button></td></tr>';
var _urls_counter = <?php echo $_counter?>;
$('add_new_option_button').observe('click', function(){
$('attribute-options-table').insert(_form_html_row.replace(/\{\{id\}\}/ig, _urls_counter));
_urls_counter++;
});
//]]></script>
</td>
</tr>
Сохранение данных при сохранении
app/code/[codepool]/[Namespace]/[Module]/controllers/Adminhtml/[Module]Controller.php
class [Namespace]_[Module]_Adminhtml_[Module]Controller
extends Mage_Adminhtml_Controller_Action
{
public function saveAction()
{
if ( $this->getRequest()->getPost() )
{
try {
$postData = $this->getRequest()->getPost();
// Save the data
$model = Mage::getModel('[namespace]_[module]/object');
$urls = $postData['urls'];
unset($postData['urls']);
$model->setData($postData);
$model->save();
$parentId = $model->getId();
// save urls
if (!empty($urls))
{
foreach ($urls['delete'] as $_key => $_row)
{
$delete = (int)$_row;
$urlsData = $urls['value'][$_key];
$_urls = Mage::getModel('[namespace]_[module]/[urls]')->load((int)$urlsData['id']); // this is the model that stores the URLs data in a second table
if ($delete && 0 < (int)$_urls->getId()) // exists & required to delete
{
$_urls->delete();
continue;
}
if (!$delete)
{
if (0 == (int)$_urls->getId()) // new item
{
Mage::getModel('[namespace]_[module]/[urls]')->setData(array(
'parent_id' => $parentId,
'label' => $urlsData['label'],
'url' => $urlsData['url'],
'sortorder' => $urlsData['sortorder'],
))->save();
}
else
{
$_urls->addData(array(
'store_id' => $parentId,
'label' => $urlsData['label'],
'url' => $urlsData['url'],
'sortorder' => $urlsData['sortorder'],
))->save();
}
}
}
}
// And wrap up the transaction
Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('adminhtml')->__('Item was successfully saved'));
[...]
$this->_redirect('*/*/');
return;
} catch (Exception $e) {
[...]
}
}
$this->_redirect('*/*/');
}
}
Теперь ранее я ссылался на метод getUrls
в объектной модели. Это выглядело бы как-то вот так.
app/code/[codepool]/[Namespace]/[Module]/Model/[Object].php
class [Namespace]_[Module]_Model_[Object] extends Mage_Core_Model_Abstract
{
public function getOpeningHours()
{
return Mage::getModel('[namespace]_[module]/urls')->getCollection()
->addFieldToFilter('parent_id', $this->getId());
}
}
И это все!
Все гораздо проще. Я описал это полностью на http://www.integer-net.com/2015/03/17/how-to-create-tables-in-magento-system-configuration/. Короче говоря:
System.xml :
<shipping_costs translate="label">
<label>Shipping Cost based on Price</label>
<frontend_model>namespace_module/config_shippingCosts</frontend_model>
<backend_model>adminhtml/system_config_backend_serialized_array</backend_model>
<sort_order>10</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>0</show_in_store>
</shipping_costs>
Как вы можете видеть, код добавляет только внешнюю модель и внутреннюю модель к обычному определению новых полей.
Внутренняя модель используется для изменения сохранения значения поля в базу данных и загрузки из нее. Всегда используйте adminhtml/system_config_backend_serialized_array для администратора здесь. Модель интерфейса на самом деле представляет собой блок, несмотря на свое название. Он используется для отображения таблицы с определенными столбцами. Интерфейсные модели всегда наследуются от класса Mage_Adminhtml_Block_System_Config_Form_Field_Array_Abstract.
В моем примере класс модели интерфейса выглядит следующим образом:
<?php
class Namespace_Module_Block_Config_ShippingCosts
extends Mage_Adminhtml_Block_System_Config_Form_Field_Array_Abstract
{
public function _prepareToRender()
{
$this->addColumn('from_price', array(
'label' => Mage::helper('namespace_module')->__('From Price'),
'style' => 'width:100px',
));
$this->addColumn('cost', array(
'label' => Mage::helper('namespace_module')->__('Shipping Cost'),
'style' => 'width:100px',
));
$this->_addAfter = false;
$this->_addButtonLabel = Mage::helper('namespace_module')->__('Add');
}
}
Больше ничего не требуется для отображения таблицы с двумя столбцами по 100 пикселей каждый.
Если вы хотите где-то использовать значения из конфигурации, вам просто нужно отменить сериализацию данные поля:
$shippingCosts = Mage::getStoreConfig('namespace_module/general/shipping_costs');
if ($shippingCosts) {
$shippingCosts = unserialize($shippingCosts);
if (is_array($shippingCosts)) {
foreach($shippingCosts as $shippingCostsRow) {
$fromPrice = $shippingCostsRow['from_price'];
$cost = $shippingCostsRow['cost'];
...
}
} else {
// handle unserializing errors here
}
}