Как изменить дату в динамическом списке при нажатии на ячейку

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Работа с динамическим списком в 1С:Предприятии 8.3 часто вызывает вопросы, когда дело касается интерактивного изменения данных. Динамический список предназначен прежде всего для отображения данных, а не для их прямого редактирования, как в таблице значений. Однако существуют сценарии, когда пользователю необходимо нажать на дату в списке, ввести количество дней и увидеть обновленный результат. В этой статье мы подробно разберем, как реализовать такой функционал, учитывая особенности различных типов данных (документы и регистры сведений).

Постановка задачи и анализ ограничений

Рассмотрим ситуацию: у нас есть форма со списком, и мы хотим, чтобы при нажатии на колонку с датой открывалось окно ввода числа, после чего дата в строке должна измениться. Здесь важно разделять два подхода:

  1. Изменение отображения: когда данные в базе остаются прежними, а меняется только картинка в списке (через параметры запроса или условное оформление).
  2. Изменение данных в базе: когда после ввода числа программа реально перезаписывает объект или запись регистра, и список обновляется автоматически.

Проанализируем ситуацию, описанную в обсуждении. Основная сложность возникла при попытке изменить запись Регистра сведений, так как стандартный метод ПолучитьОбъект(), работающий для справочников и документов, не применим к ключу записи регистра.

Способ 1. Программное изменение объекта (Запись в базу данных)

Это самый надежный способ, если изменение должно быть зафиксировано. Разберем по шагам, как это реализовать на клиенте и сервере.

Во-первых, нам нужно перехватить нажатие на ячейку. Для этого используем событие Выбор элемента формы «Список». Проанализируем код клиентской части:


&НаКлиенте
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
    // Проверяем, что нажали именно на колонку с датой
    Если Поле.Имя = "Дата" Тогда 
        СтандартнаяОбработка = Ложь; // Отменяем открытие формы объекта
        
        ДополнительныеПараметры = Новый Структура("ТекущаяСтрока", ВыбраннаяСтрока);
        Оп = Новый ОписаниеОповещения("ПослеВводаЧисла", ЭтаФорма, ДополнительныеПараметры);
        
        // Запрашиваем у пользователя количество дней
        ПоказатьВводЧисла(Оп, 0, "Введите количество дней для сдвига (можно отрицательное)");
    КонецЕсли;
КонецПроцедуры

Во-вторых, создадим процедуру обработки оповещения, которая будет вызывать серверный контекст для изменения данных:


&НаКлиенте
Процедура ПослеВводаЧисла(Результат, ДополнительныеПараметры) Экспорт
    Если Результат = Неопределено Тогда 
        Возврат; // Пользователь нажал отмену
    КонецЕсли;
    
    // Вызываем серверный метод для изменения данных в БД
    ИзменитьДанныеНаСервере(ДополнительныеПараметры.ТекущаяСтрока, Результат);
    
    // Принудительно обновляем список, чтобы увидеть изменения
    Элементы.Список.Обновить();
КонецПроцедуры

Особенности работы с Регистром Сведений

Как выяснилось в процессе обсуждения, если динамический список построен на регистре сведений, переменная ВыбраннаяСтрока будет содержать тип РегистрСведенийКлючЗаписи. У этого типа нет метода ПолучитьОбъект(). Чтобы изменить запись, нам необходимо использовать Менеджер записи. Рассмотрим правильную реализацию серверной процедуры:


&НаСервере
Процедура ИзменитьДанныеНаСервере(КлючЗаписи, СдвигДней)
    // Если это регистр сведений (например, ЦеныНоменклатуры)
    МенеджерЗаписи = РегистрыСведений.ИмяВашегоРегистра.СоздатьМенеджерЗаписи();
    
    // Заполняем ключевые поля (измерения) из ключа записи
    ЗаполнитьЗначенияСвойств(МенеджерЗаписи, КлючЗаписи);
    
    // Считываем текущую запись из базы
    МенеджерЗаписи.Прочитать();
    
    Если МенеджерЗаписи.Выбран() Тогда
        // В 1С дата хранится в секундах. 1 день = 24 * 60 * 60 секунд.
        МенеджерЗаписи.Дата = МенеджерЗаписи.Дата + (СдвигДней * 86400);
        
        Попытка
            МенеджерЗаписи.Записать();
        Исключение
            Сообщить("Не удалось изменить запись: " + ОписаниеОшибки());
        КонецПопытки;
    КонецЕсли;
КонецПроцедуры

Способ 2. Изменение только отображения (Параметры запроса)

Если задача стоит так, чтобы изменить дату сразу для всех строк в списке без записи в базу (например, «показать, что будет, если все сроки сдвинутся на 5 дней»), лучше использовать произвольный запрос динамического списка.

Разберем, как настроить такой запрос. В свойствах динамического списка установим флаг «Произвольный запрос» и напишем следующий текст:


ВЫБРАТЬ
    Т.Ссылка КАК Ссылка,
    Т.Номер КАК Номер,
    ДОБАВИТЬКДАТЕ(Т.Дата, ДЕНЬ, &СдвигДней) КАК ДатаВиртуальная
ИЗ
    Документ.РеализацияТоваровУслуг КАК Т

Теперь мы можем управлять этим сдвигом программно. Выясним, как передать параметр в список при изменении значения на форме:


&НаКлиенте
Процедура КоличествоДнейПриИзменении(Элемент)
    // Устанавливаем параметр динамического списка
    Список.Параметры.УстановитьЗначениеПараметра("СдвигДней", Объект.КоличествоДней);
КонецПроцедуры

Этот метод работает мгновенно и не нагружает базу данных операциями записи. Однако помните, что сортировка и группировка по полю ДатаВиртуальная могут работать медленнее, чем по индексированным полям таблицы.

Способ 3. Использование события «ПриПолученииДанныхНаСервере»

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

Важный момент: Данные, измененные в этом обработчике, меняются только «в памяти» перед отрисовкой на экране. Они не сохраняются в БД. Рассмотрим пример кода:


&НаСервере
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
    // Получаем значение сдвига из реквизита формы
    Сдвиг = ЭтаФорма.ЧислоДнейСдвига; 
    
    Для Каждого СтрокаСписок Из Строки Цикл
        ДанныеСтроки = СтрокаСписок.Значение;
        // Добавляем дни к дате в отображаемых данных
        ДанныеСтроки.Дата = ДанныеСтроки.Дата + (Сдвиг * 86400);
    КонецЦикла;
КонецПроцедуры

Ограничение метода: Если вы используете этот способ, стандартный поиск 1С по колонке «Дата» будет работать по старым значениям (тем, что в базе), а не по тем, что вы «нарисовали» в списке. Это часто путает пользователей.

Итоги и рекомендации

Выбор метода зависит от бизнес-задачи:

  1. Если нужно реально изменить документ/запись — используйте первый способ с событием Выбор и Менеджером записи (или ПолучитьОбъект).
  2. Если нужно массовое визуальное смещение для анализа — используйте параметры в произвольном запросе с функцией ДОБАВИТЬКДАТЕ.
  3. Если динамический список кажется слишком жестким для ваших задач (нужно менять ячейки как в Excel без записи) — рассмотрите возможность использования Таблицы значений вместо динамического списка.

Помните, что динамический список — это мощный инструмент для работы с большими объемами данных, но он требует понимания механизмов взаимодействия клиента и сервера.

← На главную