Попытка сделать "самопополняющийся" listbox-multiple с migx-записями
0. MODX Revo 2.8.8, Migx 3.0.2-beta1
1. Есть определённый набор сущностей: name+description (migx-конфигурация symptoms_config)
2. Хочу создать список множественного выбора с возможностью его пополнения через кнопку и всплывающую форму
Предпринятые шаги:
1. Создал TV symptoms_selector — список, множественный выбор
Возможные значения:
@EVAL return $modx->runSnippet('getSymptomsList');2. Создал сниппет getSymptomsList для связи «Название-Id»
$query = $modx->newQuery('migxConfigElement');
$query->where(array('config_id' => 16)); // ID конфигурации symptoms_config
$symptoms = $modx->getCollection('migxConfigElement', $query);
$output = array();
foreach ($symptoms as $symptom) {
$fields = $modx->fromJSON($symptom->get('fields'));
$output[] = $fields['name'] . '==' . $symptom->get('id');
}
return implode('||', $output);3. Создал дополнительный плагин на onDocFormRender
Он добавляет кнопку рядом с этим мультиселектом и вызывает форму заполнения новой сущности
Всё в порядке — форма открывается, поля на месте.
Но сохраняться эта штука никуда не хочет:)))
Ниже полный код этого плагина (на всякий случай). Загвоздка именно в том, как через Migx-коннектор/Migx-процессор сохранить новое значение и автоматически подставить его в выбранные… Ну и чтобы для следующих страниц была возможность выбрать его.
<?php
if ($modx->event->name == 'OnDocFormRender') {
$resourceId = isset($_REQUEST['id']) ? (int)$_REQUEST['id'] : 0;
if ($resourceId > 0) {
$resource = $modx->getObject('modResource', $resourceId);
$resourceTmplId = $resource->get('template');
if ($resource && $resourceTmplId > 0) {
$template = $modx->getObject('modTemplate', $resourceTmplId);
$symptomTV = $modx->getObject('modTemplateVar', ['name' => 'symptoms_selector']);
if ($symptomTV) {
$tvId = $symptomTV->get('id');
$tvTemplate = $modx->getObject('modTemplateVarTemplate', [
'tmplvarid' => $tvId,
'templateid' => $resourceTmplId
]);
if ($tvTemplate) {
$customScript = "<script>Ext.onReady(function() {
// Ждём полной загрузки формы
setTimeout(function() {
const tvInput = document.querySelector('input[id=\"tvdef{$tvId}\"]');
if (tvInput) {
var tvContainer = tvInput.closest('.x-form-item');
if (tvContainer) {
// Добавляем кнопку после контейнера TV
var buttonHtml = '<div style=\"margin-top: 10px; margin-bottom: 15px;\"><button type=\"button\" onclick=\"addNewSymptomTest()\" class=\"x-btn x-btn-default-small\">+ Добавить новый симптом</button></div>';
tvContainer.insertAdjacentHTML('afterend', buttonHtml);
}
}
}, 500);
// Функция для добавления нового симптома
window.addNewSymptom = function() {
MODx.load({
xtype: 'modx-window',
title: 'Добавить новый симптом',
width: 600,
height: 400,
closeAction: 'close',
layout: 'fit', // Добавляем layout
items: [{
xtype: 'form',
id: 'symptom-add-form',
layout: 'form', // Меняем на 'form' layout
labelWidth: 120,
bodyStyle: 'padding: 15px;',
defaults: {
anchor: '100%',
msgTarget: 'under'
},
items: [{
xtype: 'textfield',
fieldLabel: 'Название',
name: 'name',
allowBlank: false,
width: '100%'
}, {
xtype: 'textarea',
fieldLabel: 'Описание',
name: 'description',
height: 200,
width: '100%',
grow: true
}]
}],
buttons: [{
text: 'Отмена',
handler: function() {
this.ownerCt.ownerCt.close();
}
}, {
text: 'Сохранить',
cls: 'primary-button',
handler: function() {
const form = Ext.getCmp('symptom-add-form');
if (form && form.getForm().isValid()) {
const values = form.getForm().getValues();
Ext.Ajax.request({
url: MODx.config.connector_url,
method: 'POST',
params: {
action: 'mgr/migx/create',
configs: 'symptoms_config',
data: Ext.encode([values])
},
success: function(response) {
var result = Ext.decode(response.responseText);
if (result.success) {
MODx.msg.alert('Успех', 'Симптом добавлен!');
this.ownerCt.ownerCt.close();
setTimeout(function() {
window.location.reload();
}, 1000);
} else {
MODx.msg.alert('Ошибка', result.message || 'Ошибка при сохранении');
}
},
failure: function(response) {
MODx.msg.alert('Ошибка', 'Ошибка при сохранении симптома');
},
scope: this
});
}
}
}]
}).show();
};
$modx->regClientStartupScript($customScript);
}
}
}
}
}Плагин пока что работает только для уже созданных ресурсов, к шаблонам которых уже прикреплено данное ТВ.Помогите, пожалуйста, «добить» уже этот функционал (Полтора дня сижу и ломаю голову и всё вокруг)… ну или предложить достойную альтернативу подобному самопополняющемуся справочнику.
Бонусный вопрос: как это дело выводить? По идее просто с помощью getImageList можно?
*UPD
url: MODx.config.connector_url, — сравнил в исходном коде с другими migx tv и там указан путь '/assets/components/migx/connector.php'. Я попробовал и его, но всё равно не работает. Предполагаю, что причина в том, что нет такого процессора 'create'.
но я не понимаю, какой процессор использовать, чтобы создать сущность
Комментарии: 4
Зачем вы опять усложняете. Где вы хотите брать список (где и как он должен обновляться)?
Уважаемый @ВитОс я как раз не хочу усложнять.
Задача казалась простой: сделать аналог мультивыбора: туда можно вбить значение, которого нет в предустановленном списке, и далее оно будет показываться.
Здесь, вместо простого строкового значения я хочу сохранять пару (название+текст) и в дальнейшем иметь возможность выбрать только что добавленный вариант. Путём некоторых размышлений пришёл к такому варианту. Храниться этот список думал в modx_migx_configelements
Если есть вариант проще и нативнее, то я Вас с удовольствием почитаю! подскажете?
Задача казалась простой: сделать аналог мультивыбора: туда можно вбить значение, которого нет в предустановленном списке, и далее оно будет показываться.
Здесь, вместо простого строкового значения я хочу сохранять пару (название+текст) и в дальнейшем иметь возможность выбрать только что добавленный вариант. Путём некоторых размышлений пришёл к такому варианту. Храниться этот список думал в modx_migx_configelements
Если есть вариант проще и нативнее, то я Вас с удовольствием почитаю! подскажете?
мне кажется если не много значений будет, то можно использовать обычный migx без кастомных баз
вот пример
самый простой вариант
создать migx color
Затем создаем migx new
создаем его getTestItems



если их будет очень много можно вместо сниппета указать запрос к bd например
вот пример
самый простой вариант
создать migx color
{
"formtabs":[
{
"MIGX_id":1,
"caption":"",
"print_before_tabs":"0",
"fields":[
{
"MIGX_id":1,
"field":"name",
"caption":"\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435",
"description":"",
"description_is_code":"0",
"inputTV":"",
"inputTVtype":"",
"validation":"",
"configs":"",
"restrictive_condition":"",
"display":"",
"sourceFrom":"config",
"sources":"",
"inputOptionValues":"",
"default":"",
"useDefaultIfEmpty":"0",
"pos":1
},
{
"MIGX_id":2,
"field":"number",
"caption":"\u041d\u043e\u043c\u0435\u0440",
"description":"",
"description_is_code":"0",
"inputTV":"",
"inputTVtype":"number",
"validation":"",
"configs":"",
"restrictive_condition":"",
"display":"",
"sourceFrom":"config",
"sources":"",
"inputOptionValues":"",
"default":"",
"useDefaultIfEmpty":"0",
"pos":2
}
],
"pos":1
}
],
"contextmenus":"",
"actionbuttons":"",
"columnbuttons":"",
"filters":"",
"extended":{
"migx_add":"",
"disable_add_item":"",
"add_items_directly":"",
"formcaption":"",
"update_win_title":"",
"win_id":"",
"maxRecords":"",
"addNewItemAt":"bottom",
"media_source_id":"",
"multiple_formtabs":"",
"multiple_formtabs_label":"",
"multiple_formtabs_field":"",
"multiple_formtabs_optionstext":"",
"multiple_formtabs_optionsvalue":"",
"actionbuttonsperrow":4,
"winbuttonslist":"",
"extrahandlers":"",
"filtersperrow":4,
"packageName":"",
"classname":"",
"task":"",
"getlistsort":"",
"getlistsortdir":"",
"sortconfig":"",
"gridpagesize":"",
"use_custom_prefix":"0",
"prefix":"",
"grid":"",
"gridload_mode":1,
"check_resid":1,
"check_resid_TV":"",
"join_alias":"",
"has_jointable":"yes",
"getlistwhere":"",
"joins":"",
"hooksnippets":"",
"cmpmaincaption":"",
"cmptabcaption":"",
"cmptabdescription":"",
"cmptabcontroller":"",
"winbuttons":"",
"onsubmitsuccess":"",
"submitparams":""
},
"permissions":{
"apiaccess":"",
"view":"",
"list":"",
"save":"",
"create":"",
"remove":"",
"delete":"",
"publish":"",
"unpublish":"",
"viewdeleted":"",
"viewunpublished":""
},
"fieldpermissions":"",
"columns":[
{
"MIGX_id":1,
"header":"\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0446\u0432\u0435\u0442\u0430",
"dataIndex":"name",
"width":"",
"sortable":"false",
"show_in_grid":1,
"customrenderer":"",
"renderer":"",
"clickaction":"",
"selectorconfig":"",
"renderchunktpl":"",
"renderoptions":"",
"editor":""
}
],
"category":""
}его подключаем например на tv_colorЗатем создаем migx new
{
"formtabs":[
{
"MIGX_id":3,
"caption":"",
"print_before_tabs":"0",
"fields":[
{
"MIGX_id":4,
"field":"selected_item",
"caption":"\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442",
"description":"\u0412\u044b\u0431\u043e\u0440 \u0438\u0437 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439",
"description_is_code":"0",
"inputTV":"",
"inputTVtype":"listbox",
"validation":"",
"configs":"",
"restrictive_condition":"",
"display":"",
"sourceFrom":"config",
"sources":"",
"inputOptionValues":"@SNIPPET getTestItems",
"default":"",
"useDefaultIfEmpty":"0",
"pos":1
},
{
"MIGX_id":5,
"field":"custom_note",
"caption":"\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0437\u0430\u043c\u0435\u0442\u043a\u0430",
"description":"\u041b\u044e\u0431\u043e\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435",
"description_is_code":"0",
"inputTV":"",
"inputTVtype":"",
"validation":"",
"configs":"",
"restrictive_condition":"",
"display":"",
"sourceFrom":"config",
"sources":"",
"inputOptionValues":"",
"default":"",
"useDefaultIfEmpty":"0",
"pos":2
}
],
"pos":1
}
],
"contextmenus":"",
"actionbuttons":"",
"columnbuttons":"",
"filters":"",
"extended":{
"migx_add":"",
"disable_add_item":"",
"add_items_directly":"",
"formcaption":"",
"update_win_title":"",
"win_id":"",
"maxRecords":"",
"addNewItemAt":"bottom",
"media_source_id":"",
"multiple_formtabs":"",
"multiple_formtabs_label":"",
"multiple_formtabs_field":"",
"multiple_formtabs_optionstext":"",
"multiple_formtabs_optionsvalue":"",
"actionbuttonsperrow":4,
"winbuttonslist":"",
"extrahandlers":"",
"filtersperrow":4,
"packageName":"",
"classname":"",
"task":"",
"getlistsort":"",
"getlistsortdir":"",
"sortconfig":"",
"gridpagesize":"",
"use_custom_prefix":"0",
"prefix":"",
"grid":"",
"gridload_mode":1,
"check_resid":1,
"check_resid_TV":"",
"join_alias":"",
"has_jointable":"yes",
"getlistwhere":"",
"joins":"",
"hooksnippets":"",
"cmpmaincaption":"",
"cmptabcaption":"",
"cmptabdescription":"",
"cmptabcontroller":"",
"winbuttons":"",
"onsubmitsuccess":"",
"submitparams":""
},
"permissions":{
"apiaccess":"",
"view":"",
"list":"",
"save":"",
"create":"",
"remove":"",
"delete":"",
"publish":"",
"unpublish":"",
"viewdeleted":"",
"viewunpublished":""
},
"fieldpermissions":"",
"columns":[
{
"MIGX_id":1,
"header":"\u0437\u0430\u043c\u0435\u0442\u043a\u0430",
"dataIndex":"custom_note",
"width":"",
"sortable":"false",
"show_in_grid":1,
"customrenderer":"",
"renderer":"",
"clickaction":"",
"selectorconfig":"",
"renderchunktpl":"",
"renderoptions":"",
"editor":""
},
{
"MIGX_id":2,
"header":"\u0426\u0432\u0435\u0442",
"dataIndex":"selected_item",
"width":"",
"sortable":"false",
"show_in_grid":1,
"customrenderer":"",
"renderer":"",
"clickaction":"",
"selectorconfig":"",
"renderchunktpl":"",
"renderoptions":"",
"editor":""
}
],
"category":""
}тут в поле selected_item в Input Option Values указан спиппетсоздаем его getTestItems
$output = [];
// Получаем TV с первым MIGX где цвет
$tv = $modx->getObject('modTemplateVar', array('name' => 'tv_color'));
if ($tv) {
$value = $tv->getValue($modx->resource->get('id'));
if (!empty($value)) {
$items = $modx->fromJSON($value);
if (is_array($items)) {
foreach ($items as $item) {
if (!empty($item['name'])) {
$output[] = $item['name'] . '==' . $item['number'];
}
}
}
}
}
return implode('||', $output);вот что получается


если их будет очень много можно вместо сниппета указать запрос к bd например
@SELECT `name`,`number` FROM `[[+PREFIX]]migx_color`Если правильно вас понял, то это то что вам нужно
@ВитОс то есть, Ваше предложение — создать одно tv для хранения, а второе для выбора из первого?
Если так, то да, согласен. Я сейчас как раз «откатился» к тому, что создал отдельную техническую страницу, завел там tv для хранения списка значений и «подсасываю» значения в другую тв-шку.
Но я чот прям хочу заморочиться на красоте решения:) И, как будто бы, всё получилось, кроме последнего, самого важного шага — сохранения migx значения путём обращения к migx через js =)
*не могу с уверенностью сказать, сколько значений там будет, так как это полностью будет зависеть от фантазии заказчика, а она у него богатая:)
Если так, то да, согласен. Я сейчас как раз «откатился» к тому, что создал отдельную техническую страницу, завел там tv для хранения списка значений и «подсасываю» значения в другую тв-шку.
Но я чот прям хочу заморочиться на красоте решения:) И, как будто бы, всё получилось, кроме последнего, самого важного шага — сохранения migx значения путём обращения к migx через js =)
*не могу с уверенностью сказать, сколько значений там будет, так как это полностью будет зависеть от фантазии заказчика, а она у него богатая:)
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.