Как отсортировать таблицу формы по реквизиту через точку (например, по родителю номенклатуры)

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

При разработке на управляемых формах 1С программисты часто сталкиваются с ограничением: стандартный метод Сортировать() для коллекций данных формы (например, табличных частей) не умеет работать с реквизитами через «точку». Если вам нужно отсортировать список материалов не просто по наименованию, а сначала по Группе (Родителю), а затем по самой Номенклатуре, вы обнаружите, что конструкция типа Объект.Материалы.Сортировать("Номенклатура.Родитель") не дает результата или вызывает ошибку. Рассмотрим подробнее, почему это происходит и какими способами можно решить эту задачу.

Почему стандартная сортировка не работает через точку

Проанализируем ситуацию: ДанныеФормыКоллекция, которой является табличная часть на форме, хранит в себе ссылки на объекты, но не хранит значения их реквизитов. Когда мы выводим на форму колонку Объект.Материалы.Номенклатура.Родитель, платформа подтягивает представление этого родителя динамически для отображения. Однако в самой структуре таблицы этой колонки как физического поля данных не существует. Метод Сортировать() работает только с теми полями, которые физически присутствуют в коллекции. Выясним, как обойти это ограничение.

Способ 1. Программная сортировка через временную таблицу значений

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

Разберем пример кода по шагам:


&НаСервере
Процедура СортироватьПоГруппамНаСервере()
    // 1. Выгружаем данные табличной части в обычную Таблицу Значений
    ТЗ = Объект.Материалы.Выгрузить();
    
    // 2. Добавляем техническую колонку для фиксации нового порядка
    ТЗ.Колонки.Добавить("_Порядок", Новый ОписаниеТипов("Число"));
    
    // 3. Используем запрос для получения данных через точку и сортировки
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    ВТ_Данные.НомерСтроки КАК ИсходныйНомер,
    |    ВТ_Данные.Номенклатура КАК Номенклатура
    |ПОМЕСТИТЬ ВТ_Исходная
    |ИЗ
    |    &ТЗ КАК ВТ_Данные
    |;
    |
    |ВЫБРАТЬ
    |    Т.ИсходныйНомер
    |ИЗ
    |    ВТ_Исходная КАК Т
    |    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СпрНоменклатура
    |        ПО Т.Номенклатура = СпрНоменклатура.Ссылка
    |УПОРЯДОЧИТЬ ПО
    |    СпрНоменклатура.Родитель.Наименование,
    |    СпрНоменклатура.Наименование";
    
    Запрос.УстановитьПараметр("ТЗ", ТЗ);
    Результат = Запрос.Выполнить().Выгрузить();
    
    // 4. Проставляем индекс порядка на основе результата запроса
    Для Сч = 0 По Результат.Количество() - 1 Цикл
        СтрокаТЗ = ТЗ[Результат[Сч].ИсходныйНомер - 1];
        СтрокаТЗ._Порядок = Сч;
    КонецЦикла;
    
    // 5. Сортируем ТЗ по техническому полю и загружаем обратно в объект
    ТЗ.Сортировать("_Порядок");
    Объект.Materials.Загрузить(ТЗ);
КонецПроцедуры

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

Способ 2. Использование вспомогательного реквизита (Оптимальный)

Если сортировка по группе требуется пользователям постоянно, лучше всего добавить вспомогательный реквизит прямо в табличную часть объекта (в метаданных). Назовем его, например, ПорядокГруппы.

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

  1. Добавляем в табличную часть Материалы реквизит ПорядокГруппы (тип: Строка).
  2. В модуле формы или в модуле объекта (в обработчике ПередЗаписью или ПриЧтенииНаСервере) заполняем этот реквизит значением Номенклатура.Родитель.Наименование.
  3. Теперь в методе Сортировать() мы можем напрямую указать это поле:

&НаКлиенте
Процедура СортироватьПоГруппе(Команда)
    // Теперь это работает, так как реквизит физически есть в коллекции
    Объект.Материалы.Сортировать("ПорядокГруппы, Номенклатура");
КонецПроцедуры

Преимущество этого метода в том, что стандартная интерактивная сортировка (клик по шапке колонки) также будет работать, если в свойстве колонки Имя реквизита порядка (SortControl) указать наш новый реквизит ПорядокГруппы. Это позволит пользователю сортировать таблицу штатными средствами платформы без написания дополнительного кода на клиенте. Для реализации упорядочивания элементов по выделенному реквизиту подойдёт инструмент пользовательской сортировки справочников.

Способ 3. Создание расчетной колонки только в форме

Проанализируем ситуацию, когда мы не хотим менять структуру метаданных (добавлять реквизиты в ТЧ объекта). Мы можем добавить реквизит только в Реквизиты формы. Рассмотрим, как это сделать:

Добавим в дерево реквизитов формы внутри Объект.Материалы новую колонку ГруппаДляСортировки. Она не будет сохраняться в базе данных, но будет доступна в коллекции на форме. Заполним её при открытии:


&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    // Заполняем вспомогательную колонку для возможности сортировки
    Для Каждого СтрокаТЧ Из Объект.Материалы Цикл
        СтрокаТЧ.ГруппаДляСортировки = СтрокаТЧ.Номенклатура.Родитель.Наименование;
    КонецЦикла;
КонецПроцедуры

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

Сравнение подходов

Выясним, какой метод выбрать в зависимости от задачи:

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

← На главную