Как программно заполнить табличную часть документа из справочника по фильтру?

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

Заполнение табличной части документа на основе данных справочника — одна из самых частых задач в 1С. Однако начинающие разработчики часто сталкиваются с ситуацией, когда код вроде бы отрабатывает без ошибок, строки добавляются, но остаются абсолютно пустыми. В этой статье мы подробно разберем, почему так происходит, как исправить ошибки типизации и как реализовать удобный механизм подбора элементов для пользователя.

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

Рассмотрим ситуацию, когда разработчик пытается программно заполнить табличную часть (ТЧ) документа через запрос. Основная ошибка кроется в несоответствии типов данных. Проанализируем типичный фрагмент кода, который приводит к «пустым строкам»:


// ОШИБОЧНЫЙ ВАРИАНТ
Запрос.Текст = 
    "ВЫБРАТЬ
    |    Номенклатура.Наименование КАК Наименование
    |ИЗ
    |    Справочник.Номенклатура КАК Номенклатура
    |ГДЕ ...";

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    НоваяСтрока = Объект.Услуги.Добавить();
    НоваяСтрока.Номенклатура = Выборка.Наименование; // Ошибка здесь!
КонецЦикла;

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

Решение №1: Исправление типов в запросе

Чтобы данные отображались корректно, нам необходимо получать из базы данных именно Ссылку на объект. Рассмотрим исправленный вариант процедуры:


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

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

Важный момент: использование поиска по наименованию ("Доп. Услуги") прямо в коде считается плохим тоном (хардкодом). Если пользователь переименует вид номенклатуры в интерфейсе, код перестанет работать. Правильнее использовать предопределенные элементы или настройки.

Решение №2: Интерактивный выбор элементов пользователем

Иногда нужно не просто «залить» все данные, а дать пользователю возможность выбрать нужные позиции из списка. Для этого используется объект СписокЗначений и метод ОтметитьЭлементы(). Здесь крайне важно помнить о разделении контекста исполнения: Клиент и Сервер.

Метод ОтметитьЭлементы() является интерактивным и может быть вызван только на клиенте. Если вызвать его в серверной процедуре, система выдаст ошибку или ничего не произойдет.

Разберем правильную схему реализации подбора через список:

  1. На сервере: Формируем список возможных вариантов с помощью запроса и возвращаем его на клиент.
  2. На клиенте: Показываем этот список пользователю для выбора (галочками).
  3. На сервере (или клиенте): Добавляем только отмеченные элементы в таблицу документа.

Пример кода реализации:


&НаКлиенте
Процедура КомандаДобавить(Команда)
    
    // 1. Получаем полный список услуг с сервера
    СписокДляВыбора = ПолучитьСписокУслугНаСервере();
    
    // 2. Интерактивно даем пользователю отметить нужные
    Если СписокДляВыбора.ОтметитьЭлементы("Выберите услуги для добавления") Тогда
        // 3. Добавляем в ТЧ только отмеченные
        Для Каждого ЭлементСписка Из СписокДляВыбора Цикл
            Если ЭлементСписка.Пометка Тогда
                НоваяСтрока = Объект.Услуги.Добавить();
                НоваяСтрока.Номенклатура = ЭлементСписка.Значение;
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
    
КонецПроцедуры

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

Решение №3: Использование стандартной формы выбора (лучшая практика)

Для платформы 1С 8.3 наиболее современным и правильным способом является открытие стандартной формы выбора справочника с установленным фильтром. Это избавляет от написания ручных запросов и позволяет использовать все возможности динамических списков (поиск, сортировка, группировка).

Проанализируем шаги реализации подбора через ОткрытьФорму():


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

После того как пользователь выберет элементы в открывшейся форме, сработает событие ОбработкаВыбора на форме вашего документа. Рассмотрим, как обработать результат:


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

Полезные советы по отладке и оптимизации

Используйте точку останова: Если вы видите, что строки добавляются пустыми, поставьте точку останова на строке НоваяСтрока.Номенклатура = .... В табло отладки проверьте тип переменной справа (через ТипЗнч(...)). Если там Тип("Строка"), а реквизит ТЧ ожидает СправочникСсылка, значит, ошибка найдена.

Метод ЗаполнитьЗначенияСвойств: Если ваша табличная часть содержит много реквизитов, совпадающих по именам с полями запроса (например, Цена, ЕдИзм, Артикул), используйте функцию ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка). Это значительно сокращает код и делает его более читаемым.

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

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

← На главную