При разработке управляемых форм в 1С:Предприятии 8.3 нередко возникает задача динамически скорректировать данные списка: изменить условие выборки, добавить дополнительные таблицы или полностью перестроить исходный запрос. Однако начинающие разработчики часто сталкиваются с ситуацией, когда в процедуре на сервере свойству ТекстЗапроса присваивается новая строка, в отладчике значение свойства действительно меняется, но на самой форме список упорно отображает прежние данные. Вызовы метода Обновить() также не приносят результата.
Разберем детально, почему так происходит, какую скрытую ошибку таит передача динамического списка в параметрах серверной процедуры, как правильно перезапустить выборку и какие подводные камни нужно учитывать при динамической модификации запросов.
Посмотрим на типичный ошибочный код, с которым сталкиваются разработчики:
&НаКлиенте
Процедура ОтборПоСтатусамПриИзменении(Элемент)
СменитьЗапрос(Список, стрЗапроса);
ЭтаФорма.ОбновитьОтображениеДанных();
Элементы.Список.Обновить();
КонецПроцедуры
&НаСервере
Процедура СменитьЗапрос(ДС, СтрокаЗапроса)
ДС.ТекстЗапроса = СтрокаЗапроса;
Элементы.Список.Обновить(); // Ошибка контекста
КонецПроцедуры
В этом коде допущены сразу две принципиальные ошибки архитектуры клиент-серверного взаимодействия управляемой формы:
Список типа ДинамическийСписок из клиентского контекста в серверную процедуру в качестве параметра ДС, платформа не передает ссылку на исходный серверный объект формы. Вместо этого сериализуется и передается ограниченная проекция данных. Присваивая ДС.ТекстЗапроса = СтрокаЗапроса, мы модифицируем эту временную копию. При возврате управления на клиент изменения не фиксируются в реальном реквизите формы, и динамический список остается с прежним текстом запроса.Обновить() принадлежит элементу формы (таблице), отображающей динамический список, и предназначен для исполнения исключительно на клиенте. Попытка вызвать Элементы.Список.Обновить() на сервере является некорректной.Для того чтобы изменения действительно применились к динамическому списку, мы должны обращаться к реквизиту формы напрямую в серверном контексте без передачи списка в параметрах.
Разберем правильную реализацию по шагам:
&НаКлиенте
Процедура ОтборПоСтатусамПриИзменении(Элемент)
// Вызываем серверную процедуру без передачи реквизита списка
СменитьЗапросНаСервере(стрЗапроса);
// Обновляем визуальное отображение таблицы на клиенте
Элементы.Список.Обновить();
КонецПроцедуры
&НаСервере
Процедура СменитьЗапросНаСервере(СтрокаЗапроса)
// Обращаемся напрямую к реквизиту формы
Список.ТекстЗапроса = СтрокаЗапроса;
// Если имя списка переменное, можно обратиться через коллекцию реквизитов:
// ЭтаФорма["Список"].ТекстЗапроса = СтрокаЗапроса;
КонецПроцедуры
Обратите внимание: свойство ПроизвольныйЗапрос у динамического списка должно быть установлено в значение Истина, иначе ручная модификация свойства ТекстЗапроса не поддерживается.
Проанализируем методы обновления, которые часто путают между собой:
Элементы.ИмяТаблицы.Обновить() — вызывается строго в контексте &НаКлиенте. Он инициирует повторный запрос к базе данных, перечитывает порцию данных в соответствии с текущими настройками и отображает обновленный результат пользователю.ЭтаФорма.ОбновитьОтображениеДанных() — выполняет перерисовку связанных элементов формы и пересчет видимости/доступности. Этот метод не перечитывает данные из базы и не перезапускает динамический список. Использовать его для обновления списка бесполезно.Когда мы программно меняем свойство ТекстЗапроса, платформа внутри перестраивает схему компоновки данных динамического списка. Это влечет за собой важные нюансы, о которых необходимо помнить:
Список.КомпоновщикНастроек. Если настройки должны сохраниться, их необходимо предварительно сохранить в переменную перед сменой запроса и затем применить повторно.ОсновнаяТаблица. В некоторых случаях после перезаписи запроса платформа может сбросить заполненное свойство ОсновнаяТаблица. В результате список теряет стандартные команды (создание, копирование, пометка на удаление), а также отключается динамическое считывание порциями. Рекомендуется явно проверять и восстанавливать основную таблицу:
Список.ТекстЗапроса = НоваяСтрокаЗапроса;
Список.ОсновнаяТаблица = "Документ.ЗаказКлиента";
Элементы.Добавить() с указанием свойства ПутьКДанным.Изменение текста запроса «на лету» — крайняя мера, чреватая ошибками. В типовых конфигурациях применяются более гибкие и безопасные методики.
Вариант 1. Установка параметров запроса
Если структура выборки одинакова, а меняются только условия, предпочтительно заранее написать в запросе параметры и управлять ими на сервере:
&НаСервере
Процедура УстановитьФильтрПоСтатусуНаСервере(ВыбранныйСтатус)
Список.Параметры.УстановитьЗначениеПараметра("Статус", ВыбранныйСтатус);
Список.Параметры.УстановитьЗначениеПараметра("ФильтроватьПоСтатусу", ЗначениеЗаполнено(ВыбранныйСтатус));
КонецПроцедуры
Вариант 2. Использование расширения языка запросов компоновки данных
Для необязательных условий используйте синтаксис фигурных скобок {ГДЕ ...}. В этом случае условие попадает в результирующий SQL-запрос только тогда, когда активен соответствующий отбор, без ручной склейки строк:
ВЫБРАТЬ
Док.Ссылка,
Док.Номер,
Док.Дата,
Док.Статус
ИЗ
Документ.ЗаказКлиента КАК Док
{ГДЕ
Док.Статус = &Статус}
Вариант 3. Программное управление отборами
Самый безопасный способ фильтрации — использование коллекции Список.Отбор.Элементы. Это сохраняет производительность динамического считывания, оставляет нетронутой структуру схемы компоновки и не сбрасывает интерфейсные настройки таблицы.