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