Ограничение диапазона значений

Библиотека Cleave.js предоставляет инструменты для форматирования пользовательского ввода, однако контроль диапазона допустимых значений требует дополнительной логики. Особенно это важно при работе с числовыми полями, денежными суммами, процентами, временем, возрастом, количеством товаров, рейтингами и любыми другими данными, имеющими минимальные и максимальные ограничения.

Проблема отсутствия встроенного диапазона

Cleave.js отвечает прежде всего за:

  • форматирование ввода;
  • разделители;
  • маски;
  • преобразование структуры значения;
  • визуальное представление.

Проверка диапазона значений не входит в базовый функционал библиотеки. Например:

new Cleave('.input', {
    numeral: true
});

Такое поле позволит вводить:

1
100
999999999
-5000

Даже если логически допустим только диапазон от 1 до 100.

Поэтому ограничение диапазона реализуется вручную через:

  • события onValueChanged;
  • DOM-события input;
  • пользовательскую валидацию;
  • автоматическую корректировку значений;
  • взаимодействие с HTML-атрибутами;
  • интеграцию с фреймворками.

Минимальное и максимальное значение

Наиболее распространённый сценарий — ограничение числового диапазона.

Пример: диапазон от 1 до 100

<input type="text" class="quantity">
const cleave = new Cleave('.quantity', {
    numeral: true,
    numeralIntegerScale: 3,
    
    onValueChanged: function(event) {
        let value = parseInt(event.target.rawValue || 0);

        if (value < 1) {
            value = 1;
        }

        if (value > 100) {
            value = 100;
        }

        event.target.value = value;
    }
});

Как работает механизм

rawValue содержит неформатированное значение:

event.target.rawValue

Если пользователь вводит:

150

логика автоматически изменит значение:

100

Использование setRawValue

Прямое изменение event.target.value не всегда синхронизируется с внутренним состоянием Cleave.js. Более корректным вариантом считается использование метода setRawValue.

Правильный способ изменения значения

const cleave = new Cleave('.quantity', {
    numeral: true,

    onValueChanged: function(event) {
        let value = Number(event.target.rawValue);

        if (value > 5000) {
            cleave.setRawValue(5000);
        }
    }
});

Преимущества setRawValue

Метод:

  • обновляет внутреннее состояние;
  • корректно применяет форматирование;
  • синхронизирует rawValue;
  • предотвращает визуальные ошибки;
  • не ломает маску ввода.

Ограничение отрицательных значений

Во многих интерфейсах отрицательные числа недопустимы.

Блокировка отрицательных значений

new Cleave('.price', {
    numeral: true,
    numeralPositiveOnly: true
});

Особенности numeralPositiveOnly

Опция автоматически:

  • запрещает символ -;
  • удаляет отрицательный знак;
  • не позволяет вводить отрицательные суммы.

Ограничение длины числа

Иногда диапазон задаётся не числовыми пределами, а количеством цифр.

Ограничение до четырёх цифр

new Cleave('.code', {
    numeral: true,
    numeralIntegerScale: 4
});

Поведение numeralIntegerScale

Если указано:

numeralIntegerScale: 4

то пользователь сможет ввести максимум:

9999

Попытка ввода пятой цифры будет проигнорирована.


Ограничение десятичной части

Для финансовых данных требуется строгий контроль количества знаков после запятой.

Пример ограничения дробной части

new Cleave('.money', {
    numeral: true,
    numeralDecimalScale: 2
});

Результат

Допустимые значения:

10
10.5
10.55

Недопустимо:

10.555

Ограничение диапазона для процентов

Процентные значения обычно находятся в диапазоне:

0–100

Пример поля процентов

<input type="text" class="percent">
const percent = new Cleave('.percent', {
    numeral: true,
    numeralPositiveOnly: true,
    numeralDecimalScale: 2,

    onValueChanged: function(event) {
        let value = parseFloat(event.target.rawValue);

        if (isNaN(value)) {
            return;
        }

        if (value > 100) {
            percent.setRawValue(100);
        }
    }
});

Допустимые значения

0
45
99.99
100

Мягкое и жёсткое ограничение

Существует два подхода к ограничению диапазона.

Жёсткое ограничение

Значение немедленно исправляется:

if (value > 100) {
    cleave.setRawValue(100);
}

Мягкое ограничение

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

if (value > 100) {
    input.classList.add('error');
}

Когда применять жёсткое ограничение

Подходит для:

  • возраста;
  • количества;
  • процентов;
  • рейтингов;
  • ограниченных параметров.

Когда подходит мягкое ограничение

Используется в:

  • бухгалтерии;
  • аналитике;
  • административных интерфейсах;
  • профессиональных системах.

Ограничение диапазона даты

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

Форматирование даты

new Cleave('.date', {
    date: true,
    datePattern: ['d', 'm', 'Y']
});

Такое поле позволит вводить:

99/99/9999

если не реализовать дополнительную проверку.


Проверка диапазона дат

Пример ограничения дат

const input = document.querySelector('.date');

new Cleave(input, {
    date: true,
    datePattern: ['d', 'm', 'Y']
});

input.addEventListener('blur', () => {
    const parts = input.value.split('/');

    if (parts.length !== 3) {
        return;
    }

    const date = new Date(
        parts[2],
        parts[1] - 1,
        parts[0]
    );

    const min = new Date(2020, 0, 1);
    const max = new Date(2030, 11, 31);

    if (date < min || date > max) {
        alert('Дата вне диапазона');
    }
});

Ограничение времени

Временные интервалы также требуют дополнительной проверки.

Форматирование времени

new Cleave('.time', {
    time: true,
    timePattern: ['h', 'm']
});

Проверка диапазона времени

Допустимый интервал: 09:00–18:00

input.addEventListener('blur', () => {
    const [hours, minutes] = input.value.split(':').map(Number);

    const total = hours * 60 + minutes;

    const min = 9 * 60;
    const max = 18 * 60;

    if (total < min || total > max) {
        alert('Недопустимое время');
    }
});

Использование HTML-атрибутов min и max

При использовании input type="number" доступны встроенные ограничения HTML.

Пример

<input
    type="number"
    min="1"
    max="10"
>

Однако при использовании Cleave.js обычно применяется:

<input type="text">

Поэтому атрибуты:

min
max

не работают автоматически.


Визуальная индикация ошибок

Диапазонные ограничения часто сопровождаются отображением ошибок.

CSS-класс ошибки

.invalid {
    border-color: red;
}

Проверка диапазона

if (value < 1 || value > 100) {
    input.classList.add('invalid');
} else {
    input.classList.remove('invalid');
}

Ограничение диапазона при вводе

Проверка может происходить:

  • после завершения ввода;
  • во время ввода;
  • при потере фокуса;
  • при отправке формы.

Проверка в реальном времени

onValueChanged: function(event) {
    let value = Number(event.target.rawValue);

    if (value > 999) {
        cleave.setRawValue(999);
    }
}

Проверка при blur

input.addEventListener('blur', validate);

Проверка при submit

form.addEventListener('submit', validate);

Использование debounce

Постоянная проверка диапазона может создавать лишнюю нагрузку.

Пример debounce

function debounce(fn, delay) {
    let timeout;

    return function() {
        clearTimeout(timeout);

        timeout = setTimeout(() => {
            fn.apply(this, arguments);
        }, delay);
    };
}

Проверка с задержкой

input.addEventListener('input', debounce(() => {
    validateRange();
}, 300));

Ограничение диапазона валют

Финансовые поля особенно часто требуют диапазонного контроля.

Пример денежного поля

const salary = new Cleave('.salary', {
    numeral: true,
    prefix: '$ ',
    numeralThousandsGroupStyle: 'thousand',

    onValueChanged: function(event) {
        let value = Number(event.target.rawValue);

        if (value > 1000000) {
            salary.setRawValue(1000000);
        }
    }
});

Ограничения для финансовых данных

Часто используются:

  • минимальная сумма;
  • максимальный лимит;
  • ограничение кредита;
  • предел скидки;
  • лимит транзакции.

Ограничение диапазона в React

Пример React-компонента

import Cleave from 'cleave.js/react';
import { useState } from 'react';

function AmountInput() {
    const [value, setValue] = useState('');

    const handleChange = (e) => {
        let raw = Number(e.target.rawValue);

        if (raw > 1000) {
            raw = 1000;
        }

        setValue(raw);
    };

    return (
        <Cleave
            value={value}
            options={{
                numeral: true
            }}
            onCha nge={handleChange}
        />
    );
}

Ограничение диапазона в Vue

Пример Vue

methods: {
    onInput(event) {
        let value = Number(event.target.rawValue);

        if (value > 500) {
            value = 500;
        }

        this.amount = value;
    }
}

Комбинирование нескольких ограничений

На практике диапазон редко ограничивается одним условием.

Комплексная конфигурация

new Cleave('.input', {
    numeral: true,
    numeralPositiveOnly: true,
    numeralIntegerScale: 5,
    numeralDecimalScale: 2
});

Что ограничивает эта конфигурация

  • только положительные значения;
  • максимум 5 цифр до запятой;
  • максимум 2 цифры после запятой;
  • автоматическое форматирование числа.

Типичные ошибки

Проверка formatted value вместо rawValue

Неправильно:

Number(event.target.value)

Правильно:

Number(event.target.rawValue)

Использование parseInt для дробных чисел

Ошибка:

parseInt('10.99')

Результат:

10

Для дробных чисел необходимо:

parseFloat()

или:

Number()

Зацикливание setRawValue

Неправильная логика может вызывать рекурсивное обновление.

Проблемный код:

onValueChanged: function(event) {
    cleave.setRawValue(event.target.rawValue);
}

Практические сценарии

Возраст

18–99

Количество товара

1–1000

Процент скидки

0–100

Рейтинг

1–5

Лимит кредита

0–5000000

Время записи

09:00–18:00

Дата бронирования

01.01.2025–31.12.2025