Cleave.js предназначена для форматирования пользовательского ввода, но в контексте отправки форм ключевой задачей становится разделение визуального представления данных и их фактического значения, которое уходит на сервер. Основная сложность возникает из-за того, что отображаемое значение (с пробелами, разделителями, масками) не всегда совпадает с «чистыми» данными, необходимыми для обработки на backend.
При работе с форматированными полями важно учитывать, что Cleave.js хранит два состояния:
Именно raw value используется при отправке формы,
поскольку он не содержит символов группировки, разделителей дат или
масок телефонов.
В типичном сценарии обработка строится вокруг свойства экземпляра Cleave:
const cleave = new Cleave(input, {
phone: true,
phoneRegionCode: 'RU'
});
console.log(cleave.getRawValue());
console.log(cleave.getFormattedValue());
Отправка формы должна опираться исключительно на
getRawValue().
При стандартной отправке через <form> возникает
проблема: браузер отправляет именно значение input, которое уже
отформатировано. Поэтому требуется дополнительный слой
синхронизации.
Наиболее распространённый подход — использование скрытого поля:
<form id="userForm">
<input id="phoneInput" type="text">
<input id="phoneHidden" type="hidden" name="phone">
<button type="submit">Отправить</button>
</form>
И синхронизация через события Cleave.js:
const phoneInput = document.getElementById('phoneInput');
const hiddenInput = document.getElementById('phoneHidden');
const cleavePhone = new Cleave(phoneInput, {
phone: true,
phoneRegionCode: 'RU',
onValueChanged: function(e) {
hiddenInput.value = e.target.rawValue;
}
});
Такой подход гарантирует, что сервер получает только нормализованное значение.
Ключевой механизм интеграции с формами — событие
onValueChanged. Оно вызывается при каждом изменении поля и
предоставляет доступ к структуре:
value — текущее отображаемое значение;rawValue — очищенное значение;target — DOM-элемент.Пример обработки:
onValueChanged: function(e) {
const { rawValue, value } = e.target;
console.log('UI:', value);
console.log('SERVER:', rawValue);
}
Для отправки формы важно фиксировать именно rawValue,
так как он устойчив к форматированию и локализации.
При использовании программной отправки формы (AJAX) необходимость
скрытых полей исчезает, поскольку можно напрямую извлечь
rawValue.
const form = document.getElementById('userForm');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const payload = {
phone: cleavePhone.getRawValue()
};
await fetch('/api/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
});
В этом случае Cleave.js выступает исключительно как слой UX-форматирования, не влияющий на структуру данных запроса.
Если требуется сохранить нативную модель отправки формы, используется
FormData, но с ручной заменой значений:
form.addEventListener('submit', (e) => {
e.preventDefault();
const formData = new FormData(form);
formData.set('phone', cleavePhone.getRawValue());
fetch('/api/submit', {
method: 'POST',
body: formData
});
});
Этот подход удобен при смешанных формах, где часть полей обычная, а часть — форматированная.
В реальных интерфейсах часто присутствует несколько экземпляров Cleave.js: телефон, карта, дата. В таком случае вводится единый слой агрегации данных.
const cleavePhone = new Cleave(phoneInput, { phone: true });
const cleaveCard = new Cleave(cardInput, { creditCard: true });
const cleaveDate = new Cleave(dateInput, { date: true, datePattern: ['d', 'm', 'Y'] });
function collectData() {
return {
phone: cleavePhone.getRawValue(),
card: cleaveCard.getRawValue(),
date: cleaveDate.getRawValue()
};
}
Такой подход исключает зависимость от DOM-значений и делает слой отправки данных предсказуемым.
Отдельный слой логики часто строится вокруг проверки
rawValue. Например, телефон может быть визуально
корректным, но неполным.
function isPhoneValid(cleaveInstance) {
return cleaveInstance.getRawValue().length >= 10;
}
form.addEventListener('submit', (e) => {
e.preventDefault();
if (!isPhoneValid(cleavePhone)) {
return;
}
sendData();
});
Важно, что проверка проводится не по value, а по
очищенному значению, иначе форматирование может исказить результат.
Cleave.js позволяет менять конфигурацию на лету, что влияет и на стратегию отправки данных. При изменении типа поля (например, переключение между международным и локальным форматом телефона) необходимо учитывать, что raw значение может менять структуру.
cleavePhone.setPhoneRegionCode('US');
После таких изменений backend должен получать только
актуализированное значение getRawValue().
При использовании state-based подхода важно синхронизировать Cleave.js с состоянием приложения:
let state = {
phone: ''
};
new Cleave(input, {
phone: true,
onValueChanged: function(e) {
state.phone = e.target.rawValue;
}
});
Отправка затем полностью независима от DOM:
async function submit() {
await fetch('/api/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(state)
});
}
Такой подход устраняет необходимость обращения к input-элементам во время отправки.
Типичные проблемы возникают при неправильной интерпретации значений:
formatted value вместо
raw value;Особенно критично это для финансовых и идентификационных данных, где символы форматирования могут полностью изменить смысл строки.
Иногда возникает вопрос: очищать ли данные на клиенте или доверить это серверу. При использовании Cleave.js логика обычно смещается в сторону клиентской нормализации, поскольку библиотека уже предоставляет гарантированно «чистое» значение через API.
Однако даже в этом случае серверная валидация остаётся обязательной, так как форматирование не является защитным механизмом.
При сбросе формы через form.reset() Cleave.js не всегда
автоматически синхронизирует внутреннее состояние. Поэтому требуется
дополнительный вызов:
form.addEventListener('reset', () => {
cleavePhone.setRawValue('');
});
Без этого возможно расхождение между визуальным состоянием и данными экземпляра.
В интерфейсах с динамическими формами (модальные окна, шаговые формы) экземпляры Cleave.js часто создаются и уничтожаются. В таких сценариях отправка данных строится вокруг централизованного менеджера:
const instances = new Map();
instances.set('phone', cleavePhone);
instances.set('card', cleaveCard);
function buildPayload() {
return {
phone: instances.get('phone').getRawValue(),
card: instances.get('card').getRawValue()
};
}
Такой слой предотвращает потерю состояния при размонтировании компонентов.
Общая схема отправки данных при использовании Cleave.js выглядит как последовательность:
raw value.raw value.Такая архитектура обеспечивает стабильное разделение UI-слоя и слоя данных, сохраняя предсказуемость обработки ввода на стороне сервера.