Программное копирование узла/строки дерева значений на управляемой форме (УФ, ДанныеФормыДерево, ДанныеФормыЭлементДерева) в вариантах на клиенте и на сервере

11.01.21

Разработка - Универсальные функции

1С при интерактивном копировании строки дерева значений в управляемой форме копирует только саму строку, без его всех вложенных узлов/строк, жаль - решим! А также найдем способ передачи ДанныеФормыЭлементДерева с клиента на сервер при вставке дерева из другого элемента справочника.

Мы столкнулись с этой задачкой на следующем кейсе: пользователю в подсистеме 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, например, в публикации

Отображение и редактирование в дереве большого количества настроек/параметров/опций программы, конфигурации, документа, справочника - без программного создания элементов формы мной были рассмотрены и другие решения/ситуации по работе с деревьями значений на форме. 

Подписывайтесь на мой канал (наверху), будет много интересного бесплатного контента :)

 

Вступайте в нашу телеграмм-группу Инфостарт

См. также

Загрузка и выгрузка в Excel Универсальные функции Программист 1С:Предприятие 8 Россия Бесплатно (free)

Описанный ниже подход позволяет в три шага заполнять формулы в Excel файлы, вне зависимости от ОС сервера (MS Windows Server или Linux). Подход подразумевает отказ от работы с COM-объектом в пользу работы через "объектную модель документа" (DOM).

30.10.2025    3455    Abysswalker    8    

45

Универсальные функции Работа с интерфейсом Программист 1С:Предприятие 8 Бесплатно (free)

Порой необходимо временно отключить расширение 1С, не удаляя его, чтобы не потерять данные. Но в этом случае при каждом запуске всем будет лезть уведомление о неактивном расширении, хотя очевидно, это техническая информация, которой не стоит лишний раз пугать пользователей.

14.05.2025    6394    DeerCven    15    

57

Универсальные функции Программист 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Благодаря этим пяти строчкам можно больше не заморачиваться с загрузкой из внешних файлов. Пользуюсь везде, всегда и постоянно.

21.05.2024    48845    dimanich70    83    

170

Универсальные функции Программист 1С:Предприятие 8 1C:Бухгалтерия Абонемент ($m)

Задача: вставить картинку из буфера обмена на форму средствами платформы 1С.

1 стартмани

18.03.2024    7311    6    John_d    13    

59

Универсальные функции Программист Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Пришлось помучиться с GUID-ами немного, решил поделиться опытом, мало ли кому пригодится.

12.02.2024    61076    atdonya    31    

69

Универсальные функции Программист 1С:Предприятие 8 Бесплатно (free)

На заключительных этапах, когда идет отладка или доработка интерфейса, необходимо много раз переоткрыть внешний объект. Вот один из способов автоматизации этого.

30.11.2023    9113    ke.92@mail.ru    17    

68
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. idjumatov 17 28.10.22 13:06 Сейчас в теме
Всё бы хорошо, но когда я использую данные текущей строки в другом поле формы, при программном добавлении строки не удастся её заполнить. Метод
ЗаполнитьЗначенияСвойств(НоваяСтрока, Узел);

выдаст ошибку
Нельзя изменять поле, содержащее объект данных формы

Копирование строки дерева стандартными средствами (не программно), никаких проблем не вызывает. Проблема в том, что при этом не копируются дочерние узлы. Решения пока не нашёл, костылей хотелось бы избежать.
Для отправки сообщения требуется регистрация/авторизация