Работа с динамическим списком в 1С:Предприятии 8.3 часто вызывает вопросы, когда дело касается интерактивного изменения данных. Динамический список предназначен прежде всего для отображения данных, а не для их прямого редактирования, как в таблице значений. Однако существуют сценарии, когда пользователю необходимо нажать на дату в списке, ввести количество дней и увидеть обновленный результат. В этой статье мы подробно разберем, как реализовать такой функционал, учитывая особенности различных типов данных (документы и регистры сведений).
Рассмотрим ситуацию: у нас есть форма со списком, и мы хотим, чтобы при нажатии на колонку с датой открывалось окно ввода числа, после чего дата в строке должна измениться. Здесь важно разделять два подхода:
Проанализируем ситуацию, описанную в обсуждении. Основная сложность возникла при попытке изменить запись Регистра сведений, так как стандартный метод ПолучитьОбъект(), работающий для справочников и документов, не применим к ключу записи регистра.
Это самый надежный способ, если изменение должно быть зафиксировано. Разберем по шагам, как это реализовать на клиенте и сервере.
Во-первых, нам нужно перехватить нажатие на ячейку. Для этого используем событие Выбор элемента формы «Список». Проанализируем код клиентской части:
&НаКлиенте
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
// Проверяем, что нажали именно на колонку с датой
Если Поле.Имя = "Дата" Тогда
СтандартнаяОбработка = Ложь; // Отменяем открытие формы объекта
ДополнительныеПараметры = Новый Структура("ТекущаяСтрока", ВыбраннаяСтрока);
Оп = Новый ОписаниеОповещения("ПослеВводаЧисла", ЭтаФорма, ДополнительныеПараметры);
// Запрашиваем у пользователя количество дней
ПоказатьВводЧисла(Оп, 0, "Введите количество дней для сдвига (можно отрицательное)");
КонецЕсли;
КонецПроцедуры
Во-вторых, создадим процедуру обработки оповещения, которая будет вызывать серверный контекст для изменения данных:
&НаКлиенте
Процедура ПослеВводаЧисла(Результат, ДополнительныеПараметры) Экспорт
Если Результат = Неопределено Тогда
Возврат; // Пользователь нажал отмену
КонецЕсли;
// Вызываем серверный метод для изменения данных в БД
ИзменитьДанныеНаСервере(ДополнительныеПараметры.ТекущаяСтрока, Результат);
// Принудительно обновляем список, чтобы увидеть изменения
Элементы.Список.Обновить();
КонецПроцедуры
Как выяснилось в процессе обсуждения, если динамический список построен на регистре сведений, переменная ВыбраннаяСтрока будет содержать тип РегистрСведенийКлючЗаписи. У этого типа нет метода ПолучитьОбъект(). Чтобы изменить запись, нам необходимо использовать Менеджер записи. Рассмотрим правильную реализацию серверной процедуры:
&НаСервере
Процедура ИзменитьДанныеНаСервере(КлючЗаписи, СдвигДней)
// Если это регистр сведений (например, ЦеныНоменклатуры)
МенеджерЗаписи = РегистрыСведений.ИмяВашегоРегистра.СоздатьМенеджерЗаписи();
// Заполняем ключевые поля (измерения) из ключа записи
ЗаполнитьЗначенияСвойств(МенеджерЗаписи, КлючЗаписи);
// Считываем текущую запись из базы
МенеджерЗаписи.Прочитать();
Если МенеджерЗаписи.Выбран() Тогда
// В 1С дата хранится в секундах. 1 день = 24 * 60 * 60 секунд.
МенеджерЗаписи.Дата = МенеджерЗаписи.Дата + (СдвигДней * 86400);
Попытка
МенеджерЗаписи.Записать();
Исключение
Сообщить("Не удалось изменить запись: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Если задача стоит так, чтобы изменить дату сразу для всех строк в списке без записи в базу (например, «показать, что будет, если все сроки сдвинутся на 5 дней»), лучше использовать произвольный запрос динамического списка.
Разберем, как настроить такой запрос. В свойствах динамического списка установим флаг «Произвольный запрос» и напишем следующий текст:
ВЫБРАТЬ
Т.Ссылка КАК Ссылка,
Т.Номер КАК Номер,
ДОБАВИТЬКДАТЕ(Т.Дата, ДЕНЬ, &СдвигДней) КАК ДатаВиртуальная
ИЗ
Документ.РеализацияТоваровУслуг КАК Т
Теперь мы можем управлять этим сдвигом программно. Выясним, как передать параметр в список при изменении значения на форме:
&НаКлиенте
Процедура КоличествоДнейПриИзменении(Элемент)
// Устанавливаем параметр динамического списка
Список.Параметры.УстановитьЗначениеПараметра("СдвигДней", Объект.КоличествоДней);
КонецПроцедуры
Этот метод работает мгновенно и не нагружает базу данных операциями записи. Однако помните, что сортировка и группировка по полю ДатаВиртуальная могут работать медленнее, чем по индексированным полям таблицы.
Проанализируем ситуацию, когда нам нужно программно вычислить дату для каждой строки по сложной логике, которую нельзя описать в запросе. Для этого идеально подходит обработчик ПриПолученииДанныхНаСервере.
Важный момент: Данные, измененные в этом обработчике, меняются только «в памяти» перед отрисовкой на экране. Они не сохраняются в БД. Рассмотрим пример кода:
&НаСервере
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
// Получаем значение сдвига из реквизита формы
Сдвиг = ЭтаФорма.ЧислоДнейСдвига;
Для Каждого СтрокаСписок Из Строки Цикл
ДанныеСтроки = СтрокаСписок.Значение;
// Добавляем дни к дате в отображаемых данных
ДанныеСтроки.Дата = ДанныеСтроки.Дата + (Сдвиг * 86400);
КонецЦикла;
КонецПроцедуры
Ограничение метода: Если вы используете этот способ, стандартный поиск 1С по колонке «Дата» будет работать по старым значениям (тем, что в базе), а не по тем, что вы «нарисовали» в списке. Это часто путает пользователей.
Выбор метода зависит от бизнес-задачи:
Выбор и Менеджером записи (или ПолучитьОбъект).ДОБАВИТЬКДАТЕ.Помните, что динамический список — это мощный инструмент для работы с большими объемами данных, но он требует понимания механизмов взаимодействия клиента и сервера.