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

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




