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