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