Как в 1С получить случайное значение из перечисления и исправить ошибку "Итератор для значения не определен"?

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

При изучении разработки на платформе 1С часто возникают задачи, которые кажутся простыми, но содержат подводные камни. Одна из таких — выбор случайного значения из перечисления. В процессе можно столкнуться с ошибкой "Итератор для значения не определен", а затем — с трудностями передачи данных между сервером и клиентом. Давайте подробно разберем, как правильно решить эту задачу и избежать типичных ошибок.

Проанализируем ситуацию, с которой столкнулся начинающий разработчик. Цель — при нажатии на кнопку на форме выбрать случайное значение из перечисления (например, "Заказчик") и установить его в заголовок элемента формы.

Причина ошибки "Итератор для значения не определен"

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


Генер = Новый ГенераторСлучайныхЧисел();
СписокЗаказчиков = Новый Массив;
  // Неправильный код, который вызывает ошибку
  Для Каждого Элемент Из ПредопределенноеЗначение("Перечисление.Аспект") Цикл
	СписокЗаказчиков.Добавить(Элемент);
КонецЦикла; 
// ... дальнейший код не выполняется

Выясним причину. Функция ПредопределенноеЗначение() возвращает одно конкретное значение, а не коллекцию всех возможных значений перечисления. Цикл Для Каждого предназначен для обхода коллекций (массивов, списков, таблиц значений и т.д.). Попытка обойти в цикле одиночное значение и приводит к ошибке "Итератор для значения не определен", так как для одного элемента не существует механизма перебора.

Правильный способ получить доступ ко всем значениям перечисления — обратиться к его менеджеру напрямую через точку: Перечисления.ИмяВашегоПеречисления. Этот объект как раз и является коллекцией, которую можно использовать в цикле.

Давайте исправим код так, чтобы он корректно собирал все значения перечисления в массив.


СписокЗаказчиков = Новый Массив;
// Правильный обход всех значений перечисления "Аспект"
Для Каждого Элемент Из Перечисления.Аспект Цикл
    СписокЗаказчиков.Добавить(Элемент);
КонецЦикла;

Теперь в массиве СписокЗаказчиков будут находиться все значения из перечисления "Аспект", и мы можем двигаться дальше.

Шаг 1: Создание серверной функции для выбора случайного значения

Вся работа с данными, включая обращения к перечислениям, должна происходить на сервере. Это правило хорошего тона и архитектуры управляемых форм в 1С. Однако здесь есть важный нюанс: если нам нужно получить результат вычислений с сервера на клиенте (например, чтобы обновить заголовок поля), серверный вызов должен быть оформлен как функция, а не процедура.

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

  1. Создаем массив. В него мы поместим все значения из нашего перечисления.
  2. Заполняем массив. В цикле обходим все значения перечисления и добавляем их в массив.
  3. Генерируем случайный индекс. С помощью объекта ГенераторСлучайныхЧисел получаем случайное целое число в диапазоне от 0 до последнего индекса нашего массива. Для удобства можно использовать метод массива ВГраница(), который возвращает его верхнюю границу (индекс последнего элемента).
  4. Получаем элемент по индексу. Извлекаем из массива значение, соответствующее случайному индексу.
  5. Возвращаем результат. С помощью оператора Возврат передаем найденное значение "наружу" из функции. Важно: для установки в заголовок лучше возвращать строковое представление значения.

Посмотрим на итоговый код серверной функции:


&НаСервере
Функция ВыбратьСлучайногоЗаказчика()
    
    СписокЗаказчиков = Новый Массив;
    
    // Обращаемся к менеджеру перечисления "Заказчик"
    Для Каждого Элемент Из Перечисления.Заказчик Цикл
        СписокЗаказчиков.Добавить(Элемент);
    КонецЦикла;
    
    // Проверка, что перечисление не пустое, чтобы избежать ошибок
    Если СписокЗаказчиков.Количество() = 0 Тогда
        Возврат "Заказчик не найден"; 
    КонецЕсли;
    
    // Создаем генератор случайных чисел
    Генер = Новый ГенераторСлучайныхЧисел();
    
    // Получаем случайный индекс. Метод ВГраница() равен Количество() - 1
    Индекс = Генер.СлучайноеЧисло(0, СписокЗаказчиков.ВГраница());
    
    // Получаем случайное значение из массива
    СлучайныйЗаказчик = СписокЗаказчиков[Индекс];
    
    // Возвращаем строковое представление значения для использования на клиенте
    Возврат "" + СлучайныйЗаказчик;

КонецФункции

Шаг 2: Вызов серверной функции с клиента и обновление формы

Теперь, когда у нас есть серверная функция, которая делает всю "грязную работу" и возвращает готовый результат, нам нужно правильно вызвать её из клиентской процедуры (например, из обработчика нажатия кнопки) и использовать полученные данные.

Вот как выглядела проблемная попытка из обсуждения на форуме:


&НаКлиенте
Процедура Задача(Команда)
    ВыборЗаказчика(); // Вызов серверной процедуры, которая ничего не возвращает
    Элементы.Задача.Заголовок = "Заказ от " + Заказчик + ": Провести вычисления"; 
    // Переменная "Заказчик" на клиенте не существует, поэтому заголовок будет некорректным
КонецПроцедуры

Проблема в том, что переменная Заказчик, вычисленная на сервере, "живет" только внутри серверного вызова. Клиент о ней ничего не знает. Чтобы это исправить, нужно "поймать" результат, который возвращает наша серверная функция, в новую переменную на клиенте.

Корректная реализация клиентской процедуры:


&НаКлиенте
Процедура УстановитьСлучайныйЗаказ(Команда)

    // 1. Вызываем серверную функцию и сохраняем ее результат в клиентскую переменную
    ИмяСлучайногоЗаказчика = ВыбратьСлучайногоЗаказчика();
    
    // 2. Используем полученное значение для формирования заголовка
    // Теперь переменная ИмяСлучайногоЗаказчика содержит строку, например, "ООО Ромашка"
    Элементы.Задача.Заголовок = "Заказ от " + ИмяСлучайногоЗаказчика + ": Провести вычисления";
    
КонецПроцедуры

Таким образом, мы построили правильную и надежную схему:

Этот подход не только решает поставленную задачу, но и соответствует основным принципам разработки в управляемом режиме 1С, разделяя логику обработки данных и логику отображения.

← На главную