Как исправить проблему, когда выбранные данные из списка выбора не сохраняются в реквизите управляемой формы 1С

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При разработке на платформе «1С:Предприятие 8.3» программисты часто сталкиваются с задачей организации динамического выбора значений. Типичный пример: при выборе партнера в документе необходимо ограничить список адресов доставки только теми, которые зарегистрированы для этого контрагента. Однако на практике разработчики часто сталкиваются со следующей проблемой — пользователь успешно выбирает значение из предложенного списка, но при записи или проведении документа выбранное значение бесследно исчезает, либо поле ввода очищается.

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

В чем кроется причина проблемы: анализ механизмов платформы

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

Когда вы создаете реквизит документа АдресДоставки с типом Строка, он предназначен для хранения конкретной текстовой строки в базе данных. Список выбора (СписокВыбора) — это свойство исключительно элемента формы (поля ввода). Сам список выбора в базе данных не хранится. Он существует только в оперативной памяти компьютера пользователя (или на сервере в контексте формы) до тех пор, пока форма открыта.

Если при выборе значения из списка поле очищается или не записывается, это может происходить по следующим причинам:

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

Рассмотрим по шагам, как реализовать эту задачу правильно, надежно и в соответствии со стандартами разработки фирмы «1С».

Шаг 1. Разрушаем миф: заполнение списка выбора на сервере

Среди начинающих разработчиков бытует заблуждение, что свойство СписокВыбора элемента формы доступно для изменения исключительно в клиентских процедурах (с директивой &НаКлиенте). Из-за этого программисты создают сложные обходные пути: выгружают данные из запроса на сервере во временный реквизит формы, передают его на клиент, а затем на клиенте заполняют список выбора.

Это абсолютно неверный подход! Свойство элемента формы СписокВыбора, имеющее тип СписокЗначений, прекрасно доступно как на клиенте, так и на сервере. Мы можем напрямую обратиться к элементам формы на сервере и заполнить список выбора без использования промежуточных переменных.

Давайте посмотрим на пример правильного серверного метода для получения адресов доставки партнера:


&НаСервере
Процедура ЗаполнитьСписокВыбораАдресовНаСервере()
    
    // Очищаем текущий список выбора элемента формы
    Элементы.АдресДост.СписокВыбора.Очистить();
    
    // Если партнер не заполнен, нам нечего искать
    Если Не ЗначениеЗаполнено(Объект.Партнер) Тогда
        Возврат;
    КонецЕсли;
    
    // Формируем запрос к табличной части контактной информации партнера
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	ПартнерыКонтактнаяИнформация.Представление КАК Адрес
        |ИЗ
        |	Справочник.Партнеры.КонтактнаяИнформация КАК ПартнерыКонтактнаяИнформация
        |ГДЕ
        |	ПартнерыКонтактнаяИнформация.Ссылка = &Партнер
        |	И ПартнерыКонтактнаяИнформация.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Адрес)";
        
    Запрос.УстановитьПараметр("Партнер", Объект.Партнер);
    
    Выборка = Запрос.Выполнить().Выбрать();
    
    // Напрямую заполняем список выбора элемента формы на сервере
    Пока Выборка.Следующий() Цикл
        // Первый параметр - значение (строка), второй - представление (строка)
        Элементы.АдресДост.СписокВыбора.Добавить(Выборка.Адрес, Выборка.Адрес);
    КонецЦикла;

КонецПроцедуры

Обратите внимание: мы передаем в метод Добавить() текстовое поле Выборка.Адрес в качестве и значения, и представления. Так как реквизит документа Объект.АдресДост имеет тип Строка, типы данных полностью совпадают, и значение гарантированно запишется в базу данных.

Шаг 2. Встраивание в жизненный цикл управляемой формы

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

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

  1. ПриСозданииНаСервере: Вызывается при первом открытии новой или существующей формы.
  2. ПриЧтенииНаСервере: Вызывается при перечитывании данных из базы (например, после нажатия кнопки «Записать» или «Обновить»). Если этого не сделать, список очистится после первой же записи документа.
  3. ПриИзменении реквизита «Партнер»: Вызывается динамически на клиенте, когда пользователь интерактивно меняет партнера в документе.

Проанализируем структуру обработчиков событий формы и свяжем их воедино:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Инициализируем список выбора при открытии формы
    ЗаполнитьСписокВыбораАдресовНаСервере();
    
КонецПроцедуры

&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    
    // Восстанавливаем список выбора после чтения данных объекта с сервера
    ЗаполнитьСписокВыбораАдресовНаСервере();
    
КонецПроцедуры

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

Важный нюанс: Обратите внимание на строку Объект.АдресДост = ""; в процедуре ПартнерПриИзменении. Если ее пропустить, возникнет логическая ошибка: пользователь сменит контрагента «Ромашка» (у которого был адрес «Москва») на контрагента «Василек» (у которого адреса только в «Санкт-Петербурге»), но в документе по-прежнему останется сохранен адрес «Москва». Очистка старого значения при изменении ключевых реквизитов — это обязательное правило хорошего тона в разработке 1С.

Шаг 3. Настройка свойств элемента формы в Конфигураторе

Чтобы элемент формы вел себя как полноценный выпадающий список (комбобокс), и пользователь не мог ввести туда произвольный текст с клавиатуры (что нарушило бы целостность данных), необходимо правильно настроить свойства поля ввода в Конфигураторе:

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

Шаг 4. Современный подход с использованием БСП (Библиотеки Стандартных Подсистем)

Если вы работаете в современной типовой конфигурации (например, 1С:Управление торговлей 11, 1С:ERP или 1С:Комплексная автоматизация), прямой запрос к табличной части КонтактнаяИнформация является плохой практикой.

Структура хранения контактной информации в типовых решениях часто оптимизируется разработчиками фирмы «1С». Например, адреса могут храниться в формате JSON или XML внутри строковых полей для интеграции с государственными адресными реестрами (ФИАС / ГАР). Прямой запрос к представлению может вернуть устаревшие данные.

Для решения этой задачи правильно использовать готовые программные интерфейсы БСП. Рассмотрим, как переписать нашу серверную процедуру получения адресов с использованием общего модуля УправлениеКонтактнойИнформацией:


&НаСервере
Процедура ЗаполнитьСписокВыбораАдресовНаСервере()
    
    Элементы.АдресДост.СписокВыбора.Очистить();
    
    Если Не ЗначениеЗаполнено(Объект.Партнер) Тогда
        Возврат;
    КонецЕсли;
    
    // Используем стандартный метод БСП для получения контактной информации
    ПараметрыЗапроса = Новый Структура;
    ПараметрыЗапроса.Вставить("Ссылка", Объект.Партнер);
    ПараметрыЗапроса.Вставить("Тип", Перечисления.ТипыКонтактнойИнформации.Адрес);
    
    ТаблицаАдресов = УправлениеКонтактнойИнформацией.ПолучитьКонтактнуюИнформациюОбъекта(Объект.Партнер, ПараметрыЗапроса);
    
    Для Каждого СтрокаАдреса Из ТаблицаАдресов Цикл
        // Фильтруем только адреса доставки, если это необходимо
        Если Найти(ВРег(СтрокаАдреса.Вид), "АДРЕС ДОСТАВКИ") > 0 Тогда
            Элементы.АдресДост.СписокВыбора.Добавить(СтрокаАдреса.Представление, СтрокаАдреса.Представление);
        КонецЕсли;
    КонецЦикла;

КонецПроцедуры

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

Резюме и контрольный список для проверки

Давайте подытожим ключевые правила работы с динамическими списками выбора на управляемых формах 1С:

  1. Никогда не используйте промежуточные реквизиты формы (с типом СписокЗначений) без крайней необходимости. Это создает избыточную нагрузку на каналы связи между клиентом и сервером.
  2. Обращайтесь к свойству элемента формы СписокВыбора напрямую из процедур с директивой &НаСервере.
  3. Следите за соответствием типов данных: если реквизит документа имеет строковый тип, значение элемента списка выбора также обязано быть строкой.
  4. Всегда обновляйте список выбора в трех обработчиках: ПриСозданииНаСервере, ПриЧтенииНаСервере и при интерактивном изменении связанного реквизита (владельца списка).
  5. Обязательно очищайте старое выбранное значение реквизита при изменении реквизита-владельца на клиенте.
  6. Для типовых конфигураций отдавайте предпочтение функциям Библиотеки Стандартных Подсистем (БСП) вместо написания прямых запросов к табличным частям контактной информации.

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

← На главную