Работа с скрытыми полями

При работе с числовыми инпутами в веб-приложениях ключевая проблема заключается в различии между отображаемым значением и значением, которое должно уходить на сервер. Библиотека AutoNumeric решает эту задачу за счёт строгого разделения форматированного представления и «чистого» числового значения.

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

Базовая модель работы скрытых полей

Типовая схема интеграции выглядит следующим образом:

  • видимое поле управляется AutoNumeric
  • скрытое поле хранит числовое значение в «сыром» виде
  • при каждом изменении происходит синхронизация значений

Такой подход позволяет:

  • отделить UI-форматирование от бизнес-логики
  • исключить ошибки парсинга на сервере
  • обеспечить стабильный формат данных независимо от локали пользователя

Пример структуры DOM

<input type="text" id="price_display">
<input type="hidden" id="price_raw" name="price">

В этом случае price_display используется только для ввода и отображения, а price_raw участвует в отправке формы.

Инициализация AutoNumeric с привязкой к скрытому полю

AutoNumeric предоставляет API для получения числового значения в различных форматах:

  • getNumber()
  • getNumericString()
  • getFormatted()

Для работы со скрытым полем чаще всего используется getNumericString() или getNumber().

const displayInput = document.querySelector('#price_display');
const hiddenInput = document.querySelector('#price_raw');

const anElement = new AutoNumeric(displayInput, {
  decimalPlaces: 2,
  digitGroupSeparator: ' ',
  decimalCharacter: ','
});

Синхронизация скрытого поля через события

Основной механизм обновления скрытого поля — обработка событий изменения значения.

displayInput.addEventListener('input', () => {
  hiddenInput.value = anElement.getNumericString();
});

Такой подход обеспечивает:

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

Использование событий AutoNumeric API

Более надёжный способ — использовать встроенные события библиотеки AutoNumeric, так как они учитывают все внутренние преобразования.

anElement.domElement.addEventListener('autoNumeric:rawValueModified', () => {
  hiddenInput.value = anElement.getNumber();
});

Этот вариант предпочтительнее, поскольку:

  • учитывает вставку значений программно
  • реагирует на paste, set, update
  • исключает рассинхронизацию при внешних изменениях

Скрытые поля и отправка форм

При отправке формы важно гарантировать актуальность данных. Даже при наличии событий возможна ситуация, когда значение не синхронизировано (например, при программной установке значения непосредственно перед submit).

const form = document.querySelector('#payment_form');

form.addEventListener('submit', () => {
  hiddenInput.value = anElement.getNumericString();
});

Такой «финальный» слой синхронизации делает систему устойчивой к любым сценариям.

Работа с несколькими полями

В реальных формах часто используется набор числовых полей:

  • цена
  • скидка
  • количество
  • итог

Каждое поле имеет собственную пару display/hidden.

<input id="price_display" type="text">
<input id="price_raw" type="hidden" name="price">

<input id="discount_display" type="text">
<input id="discount_raw" type="hidden" name="discount">
const price = new AutoNumeric('#price_display', { decimalPlaces: 2 });
const discount = new AutoNumeric('#discount_display', { decimalPlaces: 2 });

function syncAll() {
  document.querySelector('#price_raw').value = price.getNumber();
  document.querySelector('#discount_raw').value = discount.getNumber();
}

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

Динамическое создание полей

В SPA и административных интерфейсах поля часто создаются динамически. AutoNumeric позволяет инициализировать новые инстансы на лету.

function createNumericField(displayId, hiddenId) {
  const display = document.createElement('input');
  const hidden = document.createElement('input');

  display.type = 'text';
  hidden.type = 'hidden';

  document.body.appendChild(display);
  document.body.appendChild(hidden);

  const an = new AutoNumeric(display, {
    decimalPlaces: 2
  });

  display.addEventListener('autoNumeric:rawValueModified', () => {
    hidden.value = an.getNumber();
  });

  return { display, hidden, an };
}

Проблема рассинхронизации и её устранение

Основные источники рассинхронизации:

  • программное изменение через set()
  • массовая перерисовка DOM
  • клонирование узлов
  • повторная инициализация AutoNumeric

Для устранения используется единая точка обновления состояния:

function updateHidden(an, hidden) {
  hidden.value = an.getNumber();
}

И применение её во всех сценариях изменения значения.

Форматирование vs сериализация данных

Важный принцип при работе со скрытыми полями и AutoNumeric заключается в разделении:

  • форматирование — только визуальный слой
  • сериализация — подготовка данных для передачи
  • хранение — только скрытое поле или модель состояния

Неправильная модель (частая ошибка):

  • отправка input.value напрямую
  • попытка парсинга строки на сервере

Корректная модель:

  • отображаемое значение не участвует в логике
  • скрытое поле всегда содержит нормализованное число

Интеграция с AJAX-запросами

При отправке данных через AJAX скрытые поля становятся источником истины:

function sendData() {
  const payload = {
    price: document.querySelector('#price_raw').value,
    discount: document.querySelector('#discount_raw').value
  };

  fetch('/api/order', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(payload)
  });
}

Использование скрытых полей снижает нагрузку на клиентскую логику сериализации и исключает зависимость от формата отображения.

Обновление значений извне

При получении данных с сервера важно синхронизировать оба уровня:

function setValue(an, hidden, value) {
  an.set(value);
  hidden.value = an.getNumber();
}

AutoNumeric гарантирует корректное форматирование при установке значения, но скрытое поле требует явного обновления.

Особенности работы с локализацией

Форматирование может включать:

  • разные разделители тысяч
  • запятую или точку как десятичный разделитель
  • валютные символы

Скрытые поля полностью абстрагируются от локали:

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

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

Поведение при очистке поля

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

  • пустое значение
  • ноль
  • null
displayInput.addEventListener('autoNumeric:rawValueModified', () => {
  const value = anElement.getNumber();
  hiddenInput.value = value === null ? '' : value;
});

Такая модель предотвращает передачу некорректных данных.

Инкапсуляция логики скрытых полей

В крупных проектах логика скрытых полей часто выносится в отдельный слой:

class NumericField {
  constructor(display, hidden, options) {
    this.hidden = hidden;
    this.an = new AutoNumeric(display, options);

    display.addEventListener('autoNumeric:rawValueModified', () => {
      this.sync();
    });
  }

  sync() {
    this.hidden.value = this.an.getNumber();
  }

  set(value) {
    this.an.set(value);
    this.sync();
  }

  get() {
    return this.an.getNumber();
  }
}

Такой подход унифицирует работу с числовыми данными и минимизирует ошибки синхронизации.

Поведение при повторной инициализации

При повторной инициализации AutoNumeric важно учитывать необходимость очистки предыдущего состояния:

  • удаление старых listeners
  • вызов destroy()
  • пересоздание скрытого поля при необходимости

Игнорирование этих шагов приводит к дублированию событий и некорректной синхронизации.

Безопасность и целостность данных

Использование скрытых полей снижает риск:

  • отправки форматированной строки вместо числа
  • потери точности при парсинге
  • ошибок локализации

При этом скрытое поле становится единственным источником данных для серверной логики, что упрощает валидацию и обработку.