Мы столкнулись с этой задачкой на следующем кейсе: пользователю в подсистеме EDIbot (конструктор веб приложений, nocode CMS, B2B порталов на 1С) было необходимо быстро вставлять готовые преформы (блоки/компоненты) в структуру страницы, а также копировать существующие преформы для возможности изменения. Структура веб страницы в подсистеме EDIbot реализована как дерево значений, и интерактивное копирование платформой 1С копирует только строчку, без вложенных в нее узлов/строк/блоков. Поэтому было решено сделать отдельные кнопки (команды), которые позволяют выполнять копирование и подбор готовых преформ со всеми вложенными узлами/строками.
Итак, вот видео с примером работы пользователя по результату выполненной модификации:
Описание: пользователь создает личный кабинет B2B портала из готовых преформ/блоков - шапки, слайдера акций (по овощам) и меню, потом добавляет еще один слайдер, изменяет источник данных - по фруктам.
Давайте разберемся, как подобное сделать Вам в своих конфигурациях.
Рассмотрим первый пример - копирование в дереве значений на управляемой форме (ДанныеФормыДерево).
Для начала получим активную строку/узел (ДанныеФормыЭлементДерева), на которой пользователь нажал кнопку "Копировать".
СтрокаТЧ = Элементы.СтруктураСтраницы.ТекущиеДанные;
Копировать будем в родителя текущего узла, поэтому получим родителя текущего узла/строки и опишем это в коде:
Куда = СтрокаТЧ.ПолучитьРодителя();
Если Куда=Неопределено Тогда
Куда = СтруктураСтраницы;
КонецЕсли;
Теперь можем вызвать нашу функцию, которая на клиенте скопирует выбранную пользователем строку в родителя:
&НаКлиенте
Функция СкопироватьУзелДерева(Узел, Куда)
Если Куда=Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
НоваяСтрока = Куда.ПолучитьЭлементы().Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Узел);
Для Каждого Элемент Из Узел.ПолучитьЭлементы() Цикл
СкопироватьУзелДерева(Элемент, НоваяСтрока);
КонецЦикла;
Возврат НоваяСтрока.ПолучитьИдентификатор();
КонецФункции
&НаКлиенте
Процедура СкопироватьУзелСтруктуры(Команда)
СтрокаТЧ = Элементы.СтруктураСтраницы.ТекущиеДанные;
Если СтрокаТЧ=Неопределено Тогда
Возврат;
КонецЕсли;
Куда = СтрокаТЧ.ПолучитьРодителя();
Если Куда=Неопределено Тогда
Куда = СтруктураСтраницы;
КонецЕсли;
ИдентификаторНовойСтроки = СкопироватьУзелДерева(СтрокаТЧ, Куда);
Если НЕ ИдентификаторНовойСтроки=Неопределено Тогда
Элементы.СтруктураСтраницы.ТекущаяСтрока = ИдентификаторНовойСтроки;
КонецЕсли;
КонецПроцедуры
Итак, первый пример мы решили, переходим ко второму - подбор и вставка узлов из другого элемента справочника. Тут сложность в том, что дерево значений хранится в реквизите элемента с типом ХранилищеЗначения, придется его получить на сервере и там же добавить в дерево значений формы (ДанныеФормыДерево) нашу структуру, решить проблему передачи ДанныеФормыЭлементДерева с клиента на сервер.
По команде нашей кнопки открывается выбор страницы, с которой мы хотим скопировать структуру:
&НаКлиенте
Процедура ПодобратьУзелСтраницы(Команда)
ОбработкаВыбораСтраницы = Новый ОписаниеОповещения("ОбработкаВыбораСтраницы", ЭтотОбъект);
ОткрытьФорму("Справочник._ВебАппСтраницы.ФормаВыбора",,,,,,ОбработкаВыбораСтраницы);
КонецПроцедуры
По завершению выбора будет вызвана процедура:
&НаКлиенте
Процедура ОбработкаВыбораСтраницы(СтраницаСсылка, ДополнительныеПараметры) экспорт
Если СтраницаСсылка=Неопределено Тогда
Возврат;
КонецЕсли;
СтрокаТЧ = Элементы.СтруктураСтраницы.ТекущиеДанные;
Если СтрокаТЧ=Неопределено Тогда
Строки = СтруктураСтраницы.ПолучитьЭлементы();
Если Строки.Количество()=0 Тогда
СтрокаТЧ = Строки.Добавить();
СтрокаТЧ.Тип = ПредопределенноеЗначение("Перечисление._ВебАппСтруктураСтраницы.Корень");
ИначеЕсли Строки.Количество()>0 Тогда
СтрокаТЧ = Строки[0];
КонецЕсли;
КонецЕсли;
ИдентификаторНовойСтроки = ДобавитьУзлыСтраницы(СтраницаСсылка, СтрокаТЧ.ПолучитьИдентификатор());
Если НЕ ИдентификаторНовойСтроки=Неопределено Тогда
Элементы.СтруктураСтраницы.ТекущаяСтрока = ИдентификаторНовойСтроки;
КонецЕсли;
КонецПроцедуры
Как видно, мы всегда предполагаем, что у нашего дерева есть корневая строка (root) и если её нет, то мы её добавляем.
Внутри идет вызов процедуры ДобавитьУзлыСтраницы, которая объявлена в контексте сервера, т.е. мы уходим с клиента на сервер и вот тут хитрость - мы не можем передать на сервер ДанныеФормыЭлементДерева, как в первом примере - получим ошибку:
Ошибка отображения типов: Отсутствует отображение для типа 'ДанныеФормыЭлементДерева' по причине: Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа. по причине: Ошибка преобразования данных XDTO: Запись значения свойства 'param': форма: Элемент имя: http://v8.1c.ru/8.2/managed-application/modules}param по причине: Ошибка отображения типов: Отсутствует отображение для типа 'ДанныеФормыЭлементДерева'
поэтому, мы будем передавать не сам тип ДанныеФормыЭлементДерева, а числовой идентификатор элемента в ДанныеФормыДерево.
Функция ДобавитьУзлыСтраницы довольно простая, ее задача получить из хранилища значений дерево значений и вызвать уже серверную функцию по копированию структуры, куда передать ДанныеФормыЭлементДерева, получив его по числовому идентификатору.
&НаСервере
Функция ДобавитьУзлыСтраницы(СтраницаСсылка, ИдентификаторРодителя)
СтруктураВыбраннойСтраницы = СтраницаСсылка.СтруктураСтраницы.Получить();
Если ТипЗнч(СтруктураВыбраннойСтраницы)=Тип("ДеревоЗначений") И СтруктураВыбраннойСтраницы.Строки.Количество()>0 Тогда
Возврат СкопироватьУзелДереваСервер(СтраницаСсылка, СтруктураВыбраннойСтраницы.Строки[0].Строки, СтруктураСтраницы.НайтиПоИдентификатору(ИдентификаторРодителя));
КонецЕсли;
Возврат Неопределено;
КонецФункции
Интересно, да? ДанныеФормыЭлементДерева есть и в контексте Сервера и в контекста Клиента, но передать его с клиента на сервер напрямую мы не можем, поэтому делаем это через идентификатор.
Теперь осталось описать функцию по копированию узлов дерева значений (СтрокаДереваЗначений) в наше дерево значений формы (ДанныеФормыДерево)
&НаСервере
Функция СкопироватьУзелДереваСервер(СтраницаСсылка, Узел, Куда)
ИдентификаторНовойСтроки = Неопределено;
Для Каждого Элемент Из Узел Цикл
НоваяСтрока = Куда.ПолучитьЭлементы().Добавить();
Если ИдентификаторНовойСтроки=Неопределено Тогда
ИдентификаторНовойСтроки = НоваяСтрока.ПолучитьИдентификатор();
КонецЕсли;
ЗаполнитьЗначенияСвойств(НоваяСтрока, Элемент);
СкопироватьУзелДереваСервер(СтраницаСсылка, Элемент.Строки, НоваяСтрока);
КонецЦикла;
Возврат ИдентификаторНовойСтроки;
КонецФункции
В итоге мы с Вами решили обе задачки по копированию, разобрались с работой ДанныеФормыДерево, передачей с клиента на сервер ДанныеФормыЭлементДерева - пользователь может копировать и вставлять/подбирать нужные ему блоки страницы веб приложения.
Надеюсь, моя публикация была Вам полезна и сэкономит Ваше время, ссылка на все публикации SizovE, например, в публикации
Отображение и редактирование в дереве большого количества настроек/параметров/опций программы, конфигурации, документа, справочника - без программного создания элементов формы мной были рассмотрены и другие решения/ситуации по работе с деревьями значений на форме.
Подписывайтесь на мой канал (наверху), будет много интересного бесплатного контента :)