Как в клиентском коде 1С понять, что ссылка не заполнена

· 9 мин

Содержание

На клиенте объект проверяют на пустую ссылку функцией ЗначениеЗаполнено(Значение): она вернёт Ложь и для пустой ссылки, и для Неопределено, и для Null. Если тип точно известен, подойдёт метод Ссылка.Пустая(). Если нужно сравнить с пустой ссылкой конкретного справочника, на тонком клиенте используют ПредопределенноеЗначение("Справочник.Имя.ПустаяСсылка"), потому что менеджер Справочники там недоступен.

Какой способ выбрать? ЗначениеЗаполнено — когда тип может быть составным или значение пришло неизвестно откуда. Пустая() — когда реквизит формы строго одного ссылочного типа. Сравнение с ПредопределенноеЗначение — когда нужно ещё и убедиться, что ссылка именно того типа. Всё это работает в тонком и веб-клиенте без серверного вызова.

Пустая ссылка, Неопределено и Null: в чём разница

Три «пустых» состояния в 1С выглядят похоже, но ведут себя по-разному. Ошибки в проверках почти всегда растут отсюда.

  • 🔹 Пустая ссылка — значение конкретного ссылочного типа, у которого нет объекта в базе. Например, СправочникСсылка.Контрагенты с нулевым идентификатором. Тип известен, объекта нет.
  • 🔹 Неопределено — значение без типа. Его содержит неинициализированная переменная, реквизит составного типа, который ещё не заполнили, результат ТекущиеДанные при пустом списке.
  • 🔹 Null — отсутствие значения в результате запроса. Чаще всего появляется при левом соединении, когда справа нет пары.

Где что встречается на практике:

Источник значенияЧто лежит, если не заполнено
Реквизит объекта одного ссылочного типа (Объект.Контрагент)пустая ссылка этого типа
Реквизит составного типа (например, субконто)Неопределено
Переменная, объявленная через ПеремНеопределено
Элементы.Список.ТекущиеДанные без выделенной строкиНеопределено
Поле выборки при левом соединении без парыNull
Параметр процедуры со значением по умолчанию НеопределеноНеопределено

Пустая ссылка не равна Неопределено. Выражение Объект.Контрагент = Неопределено для пустого реквизита одного типа вернёт Ложь, и проверка пропустит незаполненное поле.

Метод Пустая(): проверка ссылки известного типа

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

&НаКлиенте
Процедура ОрганизацияПриИзменении(Элемент)
	Если Объект.Организация.Пустая() Тогда
		Возврат;
	КонецЕсли;
	ЗаполнитьРеквизитыОрганизацииНаСервере();
КонецПроцедуры

Сильная сторона метода — явность. По коду видно, что ожидается ссылка, а не число или строка.

Слабая сторона — хрупкость. Если в переменной окажется Неопределено или Null, платформа выдаст ошибку времени выполнения:

Метод объекта не обнаружен (Пустая)

Поэтому Пустая() безопасен только в двух случаях:

  1. Реквизит объекта или формы имеет ровно один ссылочный тип, и платформа сама хранит в нём пустую ссылку.
  2. Перед вызовом вы уже проверили тип через ТипЗнч.

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

ЗначениеЗаполнено: универсальная проверка пустой ссылки на клиенте

ЗначениеЗаполнено() — функция глобального контекста. Она доступна на клиенте и на сервере и принимает значение любого типа. Для ссылок логика простая: пустая ссылка, Неопределено и Null — не заполнены, всё остальное — заполнено.

&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
	Если Не ЗначениеЗаполнено(Объект.Контрагент) Тогда
		Сообщение = Новый СообщениеПользователю;
		Сообщение.Текст = НСтр("ru = 'Укажите контрагента.'");
		Сообщение.Поле = "Объект.Контрагент";
		Сообщение.Сообщить();
		Отказ = Истина;
	КонецЕсли;
КонецПроцедуры

Функция не падает ни на одном из «пустых» состояний, поэтому её и берут по умолчанию. Но у неё есть особенность, о которой забывают: она проверяет не только ссылки.

  • 🔸 число 0 — не заполнено;
  • 🔸 пустая строка "" — не заполнена;
  • 🔸 пустая дата '00010101' — не заполнена.

Для реквизита одного ссылочного типа это не важно. А вот для составного типа, в который входят, например, справочник и число, значение 0 тоже даст Ложь. Если число ноль для вас осмысленно, сначала проверяйте тип.

&НаКлиенте
Функция СубконтоУказано(Значение)
	Если Значение = Неопределено Или Значение = Null Тогда
		Возврат Ложь;
	КонецЕсли;
	Если ТипЗнч(Значение) = Тип("Число") Тогда
		Возврат Истина; // ноль здесь допустим
	КонецЕсли;
	Возврат ЗначениеЗаполнено(Значение);
КонецФункции

Несколько обязательных ссылок сразу

Если перед действием нужно убедиться, что заполнены три-четыре реквизита, не пишите цепочку из одинаковых условий. Удобнее собрать поля в соответствие и пройти циклом: так проще добавить новое поле и вывести сообщение у каждого пустого.

&НаКлиенте
Функция ОбязательныеПоляЗаполнены()
	Поля = Новый Соответствие;
	Поля.Вставить("Организация", НСтр("ru = 'Укажите организацию.'"));
	Поля.Вставить("Контрагент", НСтр("ru = 'Укажите контрагента.'"));
	Поля.Вставить("Склад", НСтр("ru = 'Укажите склад.'"));
	ВсеЗаполнено = Истина;
	Для Каждого Поле Из Поля Цикл
		Если Не ЗначениеЗаполнено(Объект[Поле.Ключ]) Тогда
			Сообщение = Новый СообщениеПользователю;
			Сообщение.Текст = Поле.Значение;
			Сообщение.Поле = "Объект." + Поле.Ключ;
			Сообщение.Сообщить();
			ВсеЗаполнено = Ложь;
		КонецЕсли;
	КонецЦикла;
	Возврат ВсеЗаполнено;
КонецФункции

Функция не прерывается на первом пустом поле: пользователь сразу видит все незаполненные реквизиты, а не исправляет их по одному.

Сравнение способов проверить объект на пустую ссылку

На клиенте есть ещё один вариант — сравнение с пустой ссылкой нужного типа. На сервере её получают через менеджер: Справочники.Контрагенты.ПустаяСсылка(). В модуле с директивой &НаКлиенте для тонкого клиента так написать нельзя: глобальное свойство Справочники там не существует, модуль не скомпилируется с ошибкой Переменная не определена (Справочники).

Клиентская замена — функция ПредопределенноеЗначение:

&НаКлиенте
Процедура ОчиститьДоговор()
	Объект.Договор = ПредопределенноеЗначение("Справочник.ДоговорыКонтрагентов.ПустаяСсылка");
КонецПроцедуры

&НаКлиенте
Функция ДоговорНеВыбран()
	Возврат Объект.Договор = ПредопределенноеЗначение("Справочник.ДоговорыКонтрагентов.ПустаяСсылка");
КонецФункции

Строка имени собирается так: вид объекта в единственном числе, имя объекта метаданных и ПустаяСсылка. Примеры: "Документ.РеализацияТоваровУслуг.ПустаяСсылка", "Перечисление.СтавкиНДС.ПустаяСсылка". Ошибка в имени выяснится только при выполнении, поэтому имена копируйте из дерева метаданных.

Сводная таблица:

СпособРаботает на тонком клиентеНеопределено / NullПроверяет типКогда брать
ЗначениеЗаполнено(Х)давернёт Ложь, без ошибкинетпо умолчанию, составные типы
Х.Пустая()даошибка «Метод объекта не обнаружен»нетреквизит строго одного ссылочного типа
Х = ПредопределенноеЗначение("...ПустаяСсылка")давернёт Ложь (не равно)данужна пустая ссылка именно этого типа, присвоение «пустого»
Х = Справочники.Имя.ПустаяСсылка()нет, только сервер и толстый клиентвернёт Ложьдасерверный код
Х = Неопределенодаловит только Неопределено—составные типы, ТекущиеДанные

Сравнение с ПредопределенноеЗначение пропустит Неопределено: оно не равно пустой ссылке. Если реквизит составной, такая проверка даст «заполнено» на пустом поле. Для составных типов берите ЗначениеЗаполнено.

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

Строка табличной части

Самая частая связка на клиенте: сначала проверить, что строка вообще выделена, потом — что в ней выбрана ссылка.

&НаКлиенте
Процедура ОткрытьНоменклатуру(Команда)
	ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
	Если ТекущиеДанные = Неопределено Тогда
		Возврат;
	КонецЕсли;
	Если Не ЗначениеЗаполнено(ТекущиеДанные.Номенклатура) Тогда
		ПоказатьПредупреждение(, НСтр("ru = 'В строке не выбрана номенклатура.'"));
		Возврат;
	КонецЕсли;
	ПоказатьЗначение(, ТекущиеДанные.Номенклатура);
КонецПроцедуры

Проверка ТекущиеДанные = Неопределено идёт первой. Без неё обращение к ТекущиеДанные.Номенклатура упадёт на пустой табличной части.

Зависимые реквизиты

Когда контрагента очистили, договор тоже нужно сбросить. Заодно не стоит гонять серверный вызов впустую.

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

Проверка на клиенте здесь экономит обращение к серверу: при очистке поля вызова не будет вовсе.

Параметр, пришедший в форму

Параметры формы и параметры оповещения часто бывают Неопределено, если их не передали. ЗначениеЗаполнено закрывает оба случая сразу.

&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
	Если ИмяСобытия = "ЗаписанКонтрагент"
		И ЗначениеЗаполнено(Параметр)
		И Параметр = Объект.Контрагент Тогда
		ОбновитьДанныеКонтрагента();
	КонецЕсли;
КонецПроцедуры

Ошибки при проверке пустых ссылок и как их узнать

Большинство падений и «тихих» багов сводится к нескольким симптомам. Выберите свой:

Диагностика: выберите симптом

Отдельно о попытке «заглянуть» в объект через точку. На тонком клиенте нельзя прочитать реквизит по ссылке, например Объект.Контрагент.ИНН. Такой код работает только на сервере и в толстом клиенте. Если для проверки нужен реквизит связанного объекта, получайте его серверным вызовом без контекста формы.

Битая ссылка и проверка существования: только на сервере

ЗначениеЗаполнено и Пустая() отвечают на вопрос «есть ли в ссылке идентификатор». Есть ли объект в базе, они не говорят. После удаления объекта с контролем или после загрузки данных из другой базы в реквизитах остаются ссылки на несуществующие объекты. В форме они видны как <Объект не найден> с идентификатором.

Клиент таких ссылок не распознаёт. Проверяют на сервере, коротким запросом:

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

В типовых конфигурациях на Библиотеке стандартных подсистем есть готовая серверная функция ОбщегоНазначения.СсылкаСуществует. Если она есть в вашей базе, берите её, а не свою копию.

В тексте запроса пустую ссылку задают через ЗНАЧЕНИЕ(...): так не нужно передавать параметр.

ГДЕ
	Реализация.Контрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)

Для поля составного типа в запросе дополнительно проверяют ЕСТЬ NULL и = НЕОПРЕДЕЛЕНО, потому что пустое значение там может храниться по-разному.

Практика, которая окупается

  • ✅ По умолчанию — ЗначениеЗаполнено. Отступайте от неё только с причиной: нужен контроль типа или ноль допустим.
  • ✅ Проверяйте на клиенте всё, что можно проверить без данных базы. Каждый лишний серверный вызов в ПриИзменении пользователь чувствует как задержку.
  • ✅ Не дублируйте клиентскую проверку заполнения с проверкой в модуле объекта. Обязательность реквизита лучше задать свойством «Проверка заполнения» в метаданных или в обработчике ОбработкаПроверкиЗаполнения, а на клиенте оставить только то, что влияет на интерфейс.
  • ✅ Пустую ссылку для присвоения на клиенте берите из ПредопределенноеЗначение, а не из Неопределено. Так в коде явно видно, ссылка какого типа ожидается в реквизите, и сравнение с пустой ссылкой дальше по коду сработает предсказуемо.
  • ✅ Существование объекта проверяйте только там, где это реально нужно: перед обменом, при загрузке, при восстановлении данных.

Частые вопросы

Можно ли проверить пустую ссылку на веб-клиенте так же, как на тонком?
Да. ЗначениеЗаполнено, метод Пустая() и ПредопределенноеЗначение работают на веб-клиенте так же, как на тонком.
Нужен ли серверный вызов, чтобы проверить ссылку на пустоту?
Нет. Признак пустоты хранится в самой ссылке, проверка выполняется на клиенте. Сервер нужен, только чтобы узнать, существует ли объект в базе.
Чем ПустаяСсылка() отличается от ПредопределенноеЗначение с ПустаяСсылка?
Результат одинаковый: пустая ссылка нужного типа. Разница в доступности: метод менеджера работает на сервере и в толстом клиенте, ПредопределенноеЗначение — ещё и на тонком и веб-клиенте.
Как проверить, что ссылка относится к нужному справочнику?
Сравните тип: ТипЗнч(Значение) = Тип(“СправочникСсылка.Контрагенты”). Это работает на клиенте и не падает на Неопределено.
Почему ЗначениеЗаполнено вернула Истина для удалённого контрагента?
Ссылка битая, но не пустая: идентификатор в ней есть. Функция не обращается к базе. Существование объекта проверяют запросом на сервере.