Справка

Фильтрация элементов

Облачный Pyrus
Безоблачный Pyrus

Скрипты позволяют ограничивать список доступных вариантов значений для полей типа Справочник или Форма. Для этого необходимо подписаться на изменение необходимых полей формы через onChange и вызвать одну из функций установки фильтра: setFilter или setFilterAsync.

Фильтрация элементов справочника

При работе с полем типа Справочник функция фильтрации должна вернуть объект с полем values, содержащим список значений первой колонки справочника.

interface form {
    onChange(
        fieldNames: string[],
        executeOnLoad: boolean = false
    ): ChangeHandler
}

interface ChangeHandler {
    setFilter(
        fieldName: string,
        calcFilter: (state: FormState) => {
            values: string[]
        } | null
    )
    setFilterAsync(
        fieldName: string,
        calcFilterAsync: (state: FormState) => Promise<{
            values: string[]
        } | null>
    )
}

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

Рассмотрим пример: когда оператор выбирает в форме регион, в поле Город должны быть доступны только города из этого региона, а не общий список городов.

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

Чтобы фильтровать список городов по выбранному региону, добавим в скрипты формы следующий блок кода:

             // ↓ Название поля со справочником «Регионы»
form.onChange(["Регион"])
                // ↓ Название поля со справочником «Города»
  .setFilterAsync("Город", async state => {

    const [region] = state.changes;

    if (!region?.columns)
      return null;

    // Получаем значение колонки «Регион» из выбранного
    // элемента справочника «Регионы»
    const regionCol = region.columns["Регион"];

    // Получаем только города выбранного региона
    const catalogItems = await form.getCatalog('Города по регионам', [
      { columnName: 'Регион', value: regionCol, useWildcard: false }
    ]);
    const filtered = catalogItems.map(item => item.columns['Город']);

    /*
     * В переменной filtered сохранится список городов выбранного региона.
     * Например, для региона «Тульская область»:
     * ["Алексин", "Богородицк", "Тула", ...]
     *
     * Это ключи для фильтрации справочника «Города» (поле «Город»),
     * соответствующие первой (ключевой) колонке данного справочника.
     */

    return { values: filtered }
});

Метод getCatalog возвращает только значения выбранного региона, а setFilterAsync оставляет в поле «Город» только те значения, которые соответствуют выбранному региону. Если совпадений нет, возвращается { values: [] } — пустой список допустимых значений. Значение null в этом примере используется, только когда регион не выбран.

Фильтрация в поле типа Форма

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

interface form {
    onChange(
        fieldNames: string[],
        executeOnLoad: boolean = false
    ): ChangeHandler
}

interface ChangeHandler {
    setFilter(
        fieldName: string,
        calcFilter: (state: FormState) => {
            filters?: FormLinkFilter[]
        } | null
    )
    setFilterAsync(
        fieldName: string,
        calcFilterAsync: (state: FormState) => Promise<{
            filters?: FormLinkFilter[]
        } | null>
    )
}

interface FormLinkFilter {
    fieldId?: number;
    fieldName?: string;
    fieldCode?: string;
    value: FieldValue;
}

Каждое условие фильтрации FormLinkFilter включает идентификатор поля связанной формы (fieldId или fieldName или fieldCode) и значение поля.

Рассмотрим пример: при изменении поля «manager» будем фильтровать список задач в поле «contragent», показывая только те задачи связанной формы, в которых в поле «Менеджер» указан тот же пользователь, что и в поле «manager» исходной формы.

form.onChange(["manager"], true)
  .setFilter("contragent", state => {
    const [manager] = state.changes;

    if (!manager?.person_id) return null;

    return {
      filters: [{
        fieldName: "Менеджер",
        value: manager.person_id
      }]
    }
  });

Если в связанной форме фильтрация выполняется по полю типа Справочник, значение передаётся в другом формате — массивом с объектом, в котором указан идентификатор элемента справочника: value: [{ Id: item_id }].

Например, в поле Название проекта нужно показывать только те проекты, в которых в поле Клиент (поле типа Справочник) выбран тот же клиент, что и в поле Клиент исходной формы.

form.onChange(["Клиент"], true)
.setFilterAsync("Название проекта", async state => {
  const [clientField] = state.changes;

  // Если клиент не выбран — показываем все проекты
  if (!clientField || !clientField.item_id) {
    return null;
  }

  const clientItemId = clientField.item_id;

  // Возвращаем фильтр
  return {
    filters: [
      {
        fieldCode: "ClientFieldCode",
        value: [{ Id: clientItemId }], //формат для справочника
      }
    ]
  };
});

Формат значений в условиях фильтра

В условиях фильтра значения задаются в собственном формате, который отличается от описанного в статье Формат значений полей. Формат зависит от типа поля связанной формы, по которому выполняется фильтрация. Например, для поля типа Выбор нужно передать не объект { choice_id: 2 }, а массив [2].

Тип поля связанной формыФормат valueКакие задачи останутся в списке
ТекстСтрока: "Москва"Значение поля начинается с указанной строки
Число, ДеньгиЧисло: 1500Значение поля равно указанному числу
ГалочкаtrueВ поле поставлена галочка
ВыборМассив с идентификатором варианта: [2]В поле выбран указанный вариант
Выбор с множественным выборомМассив с идентификатором варианта: [2]Среди выбранных в поле вариантов есть указанный
СотрудникИдентификатор сотрудника: manager.person_idВ поле указан этот сотрудник
СправочникМассив с объектом: [{ Id: item_id }]В поле выбран указанный элемент справочника

Идентификатор варианта (choice_id) можно узнать одним из способов:

  • В консоли браузера. Когда в поле типа Форма выбрана задача, в значении поля, которое получает скрипт, есть объект fields со значениями полей этой задачи. Для поля типа Выбор в нём указаны choice_ids и choice_names. Выведите значение в консоль с помощью метода console.log (подробнее — в статье Отладка), откройте форму и выберите в поле задачу, в которой отмечен нужный вариант.
  • Через API. Варианты поля перечислены в свойстве options в описании формы, которое возвращает метод GET /forms/{form-id}. Подробнее — в статье Поля форм.

Пример скрипта, который выводит в консоль значения полей задачи, выбранной в поле «Проект»:

form.onChange(["Проект"])
  .validate("Проект", state => {
    const [project] = state.changes;

    // Например: { "Статус проекта": { choice_ids: [2], choice_names: ["В работе"] }, ... }
    console.log(project?.fields);
  });

После того как вы узнали идентификатор, удалите этот блок из скрипта.

Если в форме несколько условий, в списке останутся только задачи, которые подходят под все условия сразу.

Фильтрация по галочке

Рассмотрим пример: в поле «Подрядчик» нужно показывать только задачи связанной формы, в которых стоит галочка «Договор подписан». Фильтр включается, только если в исходной форме отмечена галочка «Только с договором».

form.onChange(["Только с договором"], true)
  .setFilter("Подрядчик", state => {
    const [onlySigned] = state.changes;

    // Галочка не отмечена — показываем все задачи
    if (!onlySigned?.checked) return null;

    return {
      filters: [{
        fieldName: "Договор подписан",
        value: true
      }]
    };
  });

Фильтрация по полю Выбор

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

form.onChange(["Только активные"], true)
  .setFilter("Проект", state => {
    const [onlyActive] = state.changes;

    if (!onlyActive?.checked) return null;

    return {
      filters: [{
        fieldName: "Статус проекта",
        value: [2] // choice_id варианта «В работе»
      }]
    };
  });

Так же задаётся фильтр по полю Выбор с множественным выбором. Например, если в связанной форме в поле «Направления» можно отметить несколько вариантов, условие value: [2] оставит в списке задачи, в которых среди отмеченных вариантов есть вариант с идентификатором 2.

Фильтр можно комбинировать с полями исходной формы. Например, чтобы показывать только проекты в статусе «В работе» и только выбранного менеджера, передайте в filters два условия:

form.onChange(["manager"], true)
  .setFilter("Проект", state => {
    const [manager] = state.changes;

    const filters = [{
      fieldName: "Статус проекта",
      value: [2] // choice_id варианта «В работе»
    }];

    if (manager?.person_id)
      filters.push({ fieldName: "Менеджер", value: manager.person_id });

    return { filters };
  });

Ограничения

  • Только одно значение в условии. Если в value для поля типа Выбор передать несколько идентификаторов, например [2, 5], учитывается только первый из них. Отобрать задачи, в которых выбран вариант «2» или «5», с помощью фильтра нельзя.
  • Нельзя отобрать незаполненные поля. Условия с пустым значением (false, null, 0, пустая строка) не применяются. Например, нельзя оставить в списке только задачи, в которых галочка не поставлена или поле Выбор не заполнено.
  • Неверные условия пропускаются без ошибки. Если поле с указанным fieldName, fieldId или fieldCode не найдено в связанной форме или значение передано в неверном формате, условие не применяется и список не фильтруется по этому полю. Если фильтр не срабатывает, проверьте название поля и формат значения по таблице выше.
  • Поля без доступа не учитываются. Если у пользователя нет доступа к полю связанной формы, условие по этому полю не применяется.

Была ли эта статья полезной?