Заполняем поле формы 1С из кода: ссылки, перечисления, составные типы
Содержание
В управляемой форме 1С 8.3 значение в поле выбора устанавливают программно через реквизит формы, к которому привязано поле, а не через сам элемент: Объект.Контрагент = НайденныйКонтрагент;. У элемента Элементы.Контрагент свойства «Значение» нет, поэтому присваивать нужно данным, а поле на экране обновится само.
Дальше всё упирается в тип реквизита и контекст выполнения. Ссылку на элемент справочника ищут на сервере, перечисление и предопределённый элемент можно получить и на клиенте, составной тип требует явной типизации. Ниже — рабочие примеры для каждого случая, платформа 8.3, управляемые формы.
Как устроено поле выбора: данные, элемент и тип
Любое поле формы — это просто окно к данным. Связь задаётся свойством элемента ПутьКДанным: например, Объект.Контрагент или Склад (реквизит самой формы). Код меняет данные, платформа перерисовывает поле.
Три вещи, которые нужно знать до первой строки кода:
- 🔗 Тип реквизита задан в метаданных. Если реквизит имеет тип
СправочникСсылка.Контрагенты, записать в него строку или число не получится: платформа приведёт значение к типу реквизита, и поле окажется пустым без всякой ошибки. - 🖥️ Клиент и сервер видят разное. Менеджеры
Справочники,Документы,Константы, запросы — только на сервере. На клиенте доступны данные формы,ПредопределенноеЗначение(),Тип(),ТипЗнч(). - 🔔 Программное присвоение не вызывает обработчик
ПриИзменении. Событие срабатывает только при интерактивном изменении. Если в обработчике есть логика (пересчёт, очистка договора), вызовите его сами.
| Тип реквизита | Где получить значение | Пример |
|---|---|---|
| Ссылка на справочник или документ | Сервер | Справочники.Склады.НайтиПоНаименованию("Основной", Истина) |
| Перечисление | Клиент и сервер | ПредопределенноеЗначение("Перечисление.ВидыОплат.Наличные") |
| Предопределённый элемент | Клиент и сервер | ПредопределенноеЗначение("Справочник.Валюты.Рубль") — если такой элемент есть в конфигурации |
| Константа | Только сервер | Константы.ВалютаУчета.Получить() |
| Строка, число, дата, булево | Клиент и сервер | Объект.Комментарий = "Срочно"; |
| Составной тип | Зависит от выбранного типа | Сначала проверка ТипЗнч(), затем присвоение |
Имена справочников, реквизитов и предопределённых элементов в примерах условные. Подставьте свои из дерева конфигурации: в типовых решениях они различаются.
Установка ссылки на справочник в поле с одним типом
Самый частый случай: на форме документа нужно подставить контрагента, склад или организацию по какому-то признаку. Поиск выполняется на сервере, присвоение — тоже там, данные формы вернутся на клиент вместе с ответом.
&НаКлиенте
Процедура ЗаполнитьКонтрагента(Команда)
ЗаполнитьКонтрагентаНаСервере("7701234567");
КонтрагентПриИзменении(Элементы.Контрагент);
Модифицированность = Истина;
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьКонтрагентаНаСервере(ИНН)
Контрагент = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", ИНН);
Если Контрагент.Пустая() Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = СтрШаблон("Контрагент с ИНН %1 не найден", ИНН);
Сообщение.Сообщить();
Возврат;
КонецЕсли;
Объект.Контрагент = Контрагент;
КонецПроцедуры
Что здесь важно:
- Методы
НайтиПоКоду,НайтиПоНаименованию,НайтиПоРеквизитупри неудаче возвращают пустую ссылку, а неНеопределено. Проверяйте через.Пустая(). НайтиПоНаименованиюбез второго параметраИстинаищет по началу строки. На «Ромашка» найдётся и «Ромашка-Сервис».НайтиПоРеквизитувозвращает первый найденный элемент. Если дубли по ИНН возможны, используйте запрос и решайте, что делать с несколькими результатами.НайтиПоРеквизитуне работает с реквизитами-строками неограниченной длины. Для них — только запрос сПОДОБНОили приведением типа.
Если элемент ищется по нескольким условиям, запрос надёжнее любого из методов менеджера:
&НаСервере
Функция НайтиДоговор(Контрагент, Организация)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Договоры.Ссылка КАК Ссылка
|ИЗ
| Справочник.ДоговорыКонтрагентов КАК Договоры
|ГДЕ
| Договоры.Владелец = &Контрагент
| И Договоры.Организация = &Организация
| И НЕ Договоры.ПометкаУдаления";
Запрос.УстановитьПараметр("Контрагент", Контрагент);
Запрос.УстановитьПараметр("Организация", Организация);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Ссылка;
КонецЕсли;
Возврат Справочники.ДоговорыКонтрагентов.ПустаяСсылка();
КонецФункции
Функция всегда возвращает значение нужного типа, поэтому Объект.Договор = НайтиДоговор(...) не испортит поле, даже если договор не найден.
Составной тип: как не получить значение «не того» типа
Реквизит составного типа (например, субконто или поле «Объект расчётов») принимает ссылки нескольких видов. Пока в нём пусто, значение равно Неопределено, и поле не знает, какой тип показывать.
Присвоить значение конкретного типа
Если ссылка уже есть, просто присвойте её: тип определится по значению. Если нужно оставить поле пустым, но «закрепить» тип, присвойте пустую ссылку:
&НаКлиенте
Процедура ЗакрепитьТипНоменклатура()
Объект.Субконто1 = ПредопределенноеЗначение("Справочник.Номенклатура.ПустаяСсылка");
КонецПроцедуры
После этого при выборе пользователь сразу попадёт в список номенклатуры, без окна выбора типа.
Проверить тип перед обработкой
Если ТипЗнч(Объект.Субконто1) = Тип("СправочникСсылка.Контрагенты") Тогда
// логика для контрагента
ИначеЕсли ЗначениеЗаполнено(Объект.Субконто1) Тогда
// любой другой заполненный тип
КонецЕсли;
Привести произвольное значение к допустимому типу
Когда значение приходит извне (из параметров, обработки, внешнего файла), используйте ОписаниеТипов.ПривестиЗначение(). Метод вернёт значение, если тип допустим, иначе — значение по умолчанию первого типа описания.
&НаСервере
Процедура УстановитьОбъектРасчетов(Значение)
ДопустимыеТипы = Новый ОписаниеТипов("СправочникСсылка.Контрагенты,СправочникСсылка.ФизическиеЛица");
Объект.ОбъектРасчетов = ДопустимыеТипы.ПривестиЗначение(Значение);
КонецПроцедуры
Сузить выбор типа на форме
Иногда реквизит составной, а в конкретной ситуации допустим один тип. Ограничьте элемент, не трогая метаданные:
Элементы.ОбъектРасчетов.ОграничениеТипа = Новый ОписаниеТипов("СправочникСсылка.Контрагенты");
Элементы.ОбъектРасчетов.ВыбиратьТип = Ложь;
ОграничениеТипа влияет только на интерактивный выбор. Код по-прежнему может записать в реквизит любой тип из метаданных, поэтому проверку ТипЗнч() не убирайте.
Перечисления, предопределённые элементы и константы
Эти значения известны заранее, поэтому их не ищут, а получают по имени.
Перечисление. На сервере можно обратиться напрямую, на клиенте — только через ПредопределенноеЗначение():
// сервер
Объект.ВидОперации = Перечисления.ВидыОперацийПоступление.Товары;
// клиент
Объект.ВидОперации = ПредопределенноеЗначение("Перечисление.ВидыОперацийПоступление.Товары");
Предопределённый элемент справочника, плана счетов, плана видов характеристик:
Объект.СчетУчета = ПредопределенноеЗначение("ПланСчетов.Хозрасчетный.ТоварыНаСкладах");
Если имя написано с ошибкой, ПредопределенноеЗначение() выдаст исключение сразу при выполнении. Это удобно: опечатка не превратится в тихо пустое поле.
Константа. Чтение только на сервере. Типичная задача — подставить значение «по умолчанию» в новый документ:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Ключ.Пустая() И Не ЗначениеЗаполнено(Объект.Валюта) Тогда
Объект.Валюта = Константы.ВалютаРегламентированногоУчета.Получить();
КонецЕсли;
КонецПроцедуры
Проверка Параметры.Ключ.Пустая() означает «форма открыта для нового объекта». Без неё код перезапишет валюту и в уже сохранённом документе.
Для значений по умолчанию лучше подходит обработчик ОбработкаЗаполнения в модуле объекта: он срабатывает при создании и из формы, и из кода, и при вводе на основании. Ещё проще — свойство реквизита Значение заполнения в конфигураторе, если значение фиксированное.
Строки табличной части и динамический список
Текущая строка табличной части
На клиенте текущую строку берут через ТекущиеДанные элемента таблицы. Обязательна проверка на Неопределено: строка может быть не выбрана.
&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
Если ТекущиеДанные.Количество = 0 Тогда
ТекущиеДанные.Количество = 1;
КонецЕсли;
ТекущиеДанные.Сумма = ТекущиеДанные.Количество * ТекущиеДанные.Цена;
КонецПроцедуры
Все строки сразу и новая строка
Массовое заполнение делайте на сервере: одно обращение вместо десятков.
&НаСервере
Процедура УстановитьСкладВоВсехСтроках(Склад)
Для Каждого Строка Из Объект.Товары Цикл
Строка.Склад = Склад;
КонецЦикла;
КонецПроцедуры
&НаСервере
Процедура ДобавитьУслугу(Номенклатура, Сумма)
НоваяСтрока = Объект.Услуги.Добавить();
НоваяСтрока.Номенклатура = Номенклатура;
НоваяСтрока.Количество = 1;
НоваяСтрока.Сумма = Сумма;
КонецПроцедуры
Когда строку нужно заполнить сразу несколькими значениями из структуры или другой строки, не перечисляйте поля вручную. Метод ЗаполнитьЗначенияСвойств() скопирует все совпадающие по имени свойства:
ДанныеСтроки = Новый Структура("Номенклатура, Количество, Цена", Номенклатура, 2, 1500);
НоваяСтрока = Объект.Товары.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, ДанныеСтроки);
НоваяСтрока.Сумма = НоваяСтрока.Количество * НоваяСтрока.Цена; // 3000
Третьим параметром можно передать список свойств через запятую, чтобы скопировать только их.
Динамический список: значение задают отбором
В строки динамического списка ничего записать нельзя: он только читает данные из базы. «Установить значение» для списка — значит задать отбор или параметр запроса.
&НаКлиенте
Процедура ОтобратьПоКонтрагенту(Контрагент)
Список.Отбор.Элементы.Очистить();
ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Контрагент");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = Контрагент;
ЭлементОтбора.Использование = Истина;
КонецПроцедуры
Если в произвольном запросе списка есть параметр &Период, его задают так: Список.Параметры.УстановитьЗначениеПараметра("Период", НачалоМесяца(ТекущаяДата()));.
В конфигурациях на БСП короче вызвать ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(): процедура сама найдёт существующий элемент отбора по полю и не будет плодить дубли.
Список.Отбор.Элементы.Очистить() снимает и пользовательские отборы. Если пользователь мог настроить свои, удаляйте только свой элемент.
Поле с режимом выбора из списка и форма выбора
Заполнить список выбора и выбрать значение
У поля ввода со свойством РежимВыбораИзСписка = Истина, переключателя или поля флажка значения задаются коллекцией СписокВыбора. Реквизит при этом остаётся обычным, и значение ставится в него:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
СписокДоставки = Элементы.СпособДоставки.СписокВыбора;
СписокДоставки.Очистить();
СписокДоставки.Добавить("Самовывоз", "Самовывоз со склада");
СписокДоставки.Добавить("Курьер", "Курьером до двери");
СписокДоставки.Добавить("ТК", "Транспортной компанией");
Если Не ЗначениеЗаполнено(Объект.СпособДоставки) Тогда
Объект.СпособДоставки = "Самовывоз";
КонецЕсли;
КонецПроцедуры
Первый параметр Добавить() — значение, которое запишется в реквизит, второй — текст на экране. Если записать в реквизит значение, которого в списке нет, оно сохранится, но поле покажет его «как есть», без красивого представления.
Ограничить выбор: параметры выбора
Чтобы в поле «Договор» выбирались только договоры текущего контрагента, задайте параметры выбора программно:
&НаСервере
Процедура УстановитьПараметрыВыбораДоговора()
Параметры = Новый Массив;
Параметры.Добавить(Новый ПараметрВыбора("Отбор.Владелец", Объект.Контрагент));
Элементы.Договор.ПараметрыВыбора = Новый ФиксированныйМассив(Параметры);
КонецПроцедуры
Если зависимость постоянная, удобнее настроить свойство СвязиПараметровВыбора в конфигураторе: обновлять параметры при смене контрагента не придётся.
Открыть форму выбора из кода
Когда нужно открыть выбор по кнопке, передайте поле владельцем формы. Значение подставится так же, как при ручном выборе:
&НаКлиенте
Процедура ВыбратьКонтрагента(Команда)
ПараметрыФормы = Новый Структура("РежимВыбора", Истина);
ОткрытьФорму("Справочник.Контрагенты.ФормаВыбора", ПараметрыФормы, Элементы.Контрагент);
КонецПроцедуры
Чтобы заменить стандартный выбор своим, используйте обработчик НачалоВыбора поля: установите СтандартнаяОбработка = Ложь и откройте свою форму или список.
Флаг модифицированности
Программное изменение данных формы не помечает форму изменённой. Если после вашей подстановки пользователь закроет окно, вопроса о сохранении не будет. Поставьте Модифицированность = Истина; явно, как в первом примере.
В обычных формах (толстый клиент) реквизиты объекта доступны в модуле формы по имени: Контрагент = НайденныйКонтрагент;. Правила типизации и поиска ссылок те же, но разделения на клиент и сервер нет.
Ошибки при программной установке значения и как их ловить
Код, который ставит значения из внешних данных (файл, обмен, параметры другой формы), имеет смысл обернуть в Попытка ... Исключение. Пользователю показывайте короткое сообщение, подробности пишите в журнал регистрации:
&НаСервере
Процедура ЗагрузитьЗначение(ДанныеИзФайла)
Попытка
Объект.Склад = Справочники.Склады.НайтиПоКоду(ДанныеИзФайла.КодСклада);
Исключение
ЗаписьЖурналаРегистрации("Загрузка склада", УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Не удалось установить склад. Подробности в журнале регистрации.";
КонецПопытки;
КонецПроцедуры
Не глушите исключение пустым блоком Исключение. Поле останется со старым значением, и никто не узнает почему.