Как исправить ошибку «Итератор для значения не определен» при выборе из формы подбора в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие 8 (особенно в управляемом приложении) программисты часто сталкиваются с ошибкой «Итератор для значения не определен». Данная ошибка может парализовать работу формы подбора или выбора, возникая буквально на «ровном месте» после незначительного изменения кода.

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

---

Причина возникновения ошибки: теория и практика

Ошибка «Итератор для значения не определен» всегда указывает на одну конкретную алгоритмическую ошибку: в коде используется обход коллекции с помощью цикла Для Каждого ... Из ... Цикл, однако переменная, которая указана после ключевого слова Из, не является коллекцией.

В платформе 1С итератор (возможность последовательного обхода элементов) определен только для ограниченного набора типов данных. К ним относятся:

Если же вы попытаетесь применить цикл Для Каждого к простым типам данных (таким как Число, Строка, Булево, Дата) или к объектным ссылкам (например, СправочникСсылка.ТранспортныеСредства), платформа незамедлительно вызовет исключение.

Давайте посмотрим на исходный код обработчика, из-за которого возникла проблема у автора темы:


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

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

---

Почему возвращается Ссылка, а не ожидаемая Структура?

Автор кода попытался переопределить стандартный выбор в форме подбора (вспомогательной форме выбора транспортного средства), чтобы передавать не просто ссылку, а структуру со специфическим реквизитом (Вместимость):


&НаКлиенте
Процедура АвтоВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    парам_Авто = Элемент.ТекущиеДанные.Вместимость;
    ОповеститьОВыборе(Новый Структура("Вместимость", парам_Авто));
КонецПроцедуры

Почему же в форму документа все равно пришла ссылка, а не структура? Разберем основные причины:

  1. Разные способы выбора на форме. Процедура АвтоВыбор привязана к событию таблицы Выбор. Оно срабатывает при двойном клике мышкой по строке или при нажатии клавиши Enter. Однако, если пользователь нажимает на стандартную кнопку «Выбрать» в командной панели формы подбора, данное событие игнорируется! Платформа выполняет стандартную процедуру выбора и возвращает ссылку на текущую строку динамического списка.
  2. Отсутствие привязки обработчика. Иногда разработчики забывают физически привязать созданную процедуру к событию элемента управления в палитре свойств формы (в поле «Выбор»).
  3. Неверный режим открытия формы подбора. Если форма была открыта без флага РежимВыбора = Истина, механизм оповещения владельца может работать некорректно.

---

Вариант решения №1. Получение данных на сервере (Рекомендуемый)

Самый простой, надежный и архитектурно правильный способ — отказаться от попыток «выдавить» дополнительные параметры напрямую из формы выбора. Позвольте форме выбора работать стандартно: возвращать ссылку на выбранный элемент справочника. Все необходимые реквизиты (в данном случае реквизит Вместимость) мы получим на сервере в неконтекстном вызове.

Такой подход гарантирует, что код не сломается при любых действиях пользователя в форме выбора (будь то двойной клик или нажатие кнопки «Выбрать»).

Рассмотрим реализацию этого метода по шагам:

Шаг 1. Изменяем код в форме документа (приемнике):


&НаКлиенте
Процедура НоменклатураОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    // Проверяем, что пользователь действительно выбрал элемент справочника
    Если ЗначениеЗаполнено(ВыбранноеЗначение) И Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(ВыбранноеЗначение)) Тогда
        
        // Вызываем серверную функцию для быстрого получения вместимости без передачи контекста формы
        ВместимостьТранспорта = ПолучитьВместимостьНаСервере(ВыбранноеЗначение);
        
        // Заполняем строку табличной части
        ТекущаяСтрока = Элементы.Номенклатура.ТекущиеДанные;
        Если ТекущаяСтрока <> Неопределено Тогда
            ТекущаяСтрока.Количество = ВместимостьТранспорта;
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Шаг 2. Создаем серверную функцию в модуле формы документа:


&НаСервереБезКонтекста
Функция ПолучитьВместимостьНаСервере(СсылкаНаТС)
    // Так как реквизиты ссылок недоступны непосредственно на клиенте, 
    // считываем реквизит "Вместимость" на стороне сервера
    Возврат СсылкаНаТС.Вместимость;
КонецФункции

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

---

Вариант решения №2. Правильная передача структуры из формы выбора

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

Проанализируем, как правильно реализовать передачу структуры:

Шаг 1. Пишем обработчик в форме выбора (источнике):

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


&НаКлиенте
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
    
    // Обязательно отменяем стандартное поведение платформы!
    СтандартнаяОбработка = Ложь; 
    
    ТекущиеДанные = Элемент.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        
        // Формируем структуру с необходимыми параметрами
        ПараметрыВыбора = Новый Структура;
        ПараметрыВыбора.Вставить("Ссылка", ВыбраннаяСтрока);
        ПараметрыВыбора.Вставить("Вместимость", ТекущиеДанные.Вместимость);
        
        // Оповещаем владельца формы о сделанном выборе
        ОповеститьОВыборе(ПараметрыВыбора);
        
    КонецЕсли;
    
КонецПроцедуры

Обратите внимание: Чтобы стандартная кнопка «Выбрать» на форме вела себя точно так же, рекомендуется в свойствах таблицы формы назначить команду выбора на созданную процедуру СписокВыбор или переопределить действие кнопки в командной панели.

Шаг 2. Обрабатываем полученную структуру в форме документа:

Поскольку теперь форма возвращает структуру, нам не нужно использовать циклы. Мы можем обратиться к свойствам структуры напрямую.


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

---

Золотые правила безопасной разработки (Defensive Programming)

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

← На главную