watchExternalChanges

В браузерных приложениях значение поля ввода может изменяться не только через действия пользователя или API самой библиотеки, но и извне: через прямое присваивание input.value, через сторонние скрипты, через реактивные фреймворки, через обновление DOM после AJAX-запросов. В таких сценариях возникает проблема рассинхронизации: форматтер чисел перестаёт соответствовать реальному значению поля.

Поведение, связанное с наблюдением за внешними изменениями, в AutoNumeric решает задачу постоянного поддержания согласованного состояния между «сырым» значением DOM и внутренним представлением библиотеки.


Базовый принцип работы наблюдения

AutoNumeric поддерживает механизм, который отслеживает изменения значения input-элемента, происходящие не через его собственные методы установки значения.

Когда включён режим наблюдения за внешними изменениями, библиотека:

  • фиксирует текущее состояние input;
  • отслеживает модификации value извне;
  • при обнаружении изменений выполняет повторный парсинг;
  • применяет форматирование согласно текущей конфигурации;
  • синхронизирует внутреннее числовое значение.

Таким образом, даже если значение изменено сторонним кодом напрямую, AutoNumeric восстанавливает корректный формат.


Типичные источники внешних изменений

Сценарии, в которых возникает необходимость наблюдения:

Прямое присваивание значения DOM

const input = document.querySelector("#price");
input.value = "1234567.89";

Без механизма наблюдения библиотека может не отреагировать на такое изменение.


Обновление через AJAX

fetch("/api/price")
  .then(r => r.json())
  .then(data => {
    input.value = data.price;
  });

Значение меняется вне контекста AutoNumeric.


Фреймворки и реактивные системы

Vue, React (через uncontrolled inputs), Angular или Svelte могут изменять DOM при ререндере.

state.price = 99999;

Если библиотека не отслеживает изменения DOM напрямую, форматирование нарушается.


Массовые DOM-операции

document.querySelectorAll(".price").forEach(el => {
  el.value = "1000";
});

При большом количестве полей необходимость синхронизации становится критичной.


Включение наблюдения за внешними изменениями

В AutoNumeric это поведение задаётся через конфигурационный параметр watchExternalChanges.

Базовая активация

const anElement = new AutoNumeric("#price", {
  watchExternalChanges: true
});

При включении параметра библиотека начинает отслеживать любые изменения value, не инициированные её собственными методами.


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

Когда внешний код меняет input.value, происходит следующий цикл:

  1. фиксируется новое строковое значение;
  2. выполняется разбор строки в число с учётом локали и настроек;
  3. проверяется валидность значения относительно ограничений (min, max);
  4. применяется форматирование (разделители, десятичные знаки);
  5. обновляется внутреннее состояние AutoNumeric.

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


Особенности работы с программным API

AutoNumeric различает два типа изменений:

  • внутренние — через методы set(), setNumericString(), upd ate();
  • внешние — прямое изменение DOM.

watchExternalChanges реагирует только на второй тип.

anElement.se t(1000); // внутреннее изменение
input.value = 2000;  // внешнее изменение

В первом случае повторная обработка не требуется, во втором — запускается синхронизация.


Ограничения и потенциальные проблемы

Избыточные перерасчёты

При частых внешних изменениях (например, в циклах или при анимациях) возможны частые переформатирования:

setInterval(() => {
  input.value = Math.random() * 10000;
}, 50);

Это может привести к дополнительной нагрузке из-за постоянного парсинга и форматирования.


Конфликты с реактивными фреймворками

В некоторых архитектурах (особенно Vue/React с controlled inputs) происходит двойное управление значением:

  • фреймворк пишет в DOM;
  • AutoNumeric перезаписывает значение обратно.

Это может приводить к эффекту «дёрганья» значения.


Потеря курсора

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


Стратегии минимизации конфликтов

Ограничение включения наблюдения

Включение watchExternalChanges целесообразно только там, где есть реальные внешние источники изменений.

const anElement = new AutoNumeric("#price", {
  watchExternalChanges: false
});

Использование программных методов вместо DOM-модификации

Вместо:

input.value = 5000;

предпочтительно:

anElement.set(5000);

Это исключает необходимость внешнего наблюдения.


Группировка обновлений

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

const values = [100, 200, 300];

values.forEach(v => anElement.set(v));

Либо использовать временное отключение логики обновления (через уничтожение и повторную инициализацию экземпляра в сложных случаях).


Взаимодействие с мутациями DOM

В некоторых реализациях наблюдение может быть реализовано через MutationObserver, отслеживающий изменения атрибута value.

Логика обычно включает:

  • наблюдение за изменением attributes;
  • проверку, изменился ли именно value;
  • игнорирование собственных изменений AutoNumeric (защита от циклов).

Защита от бесконечных циклов

Ключевая инженерная проблема — избежать ситуации:

  1. внешний код меняет value;
  2. AutoNumeric форматирует значение;
  3. DOM снова фиксируется как «изменённый извне»;
  4. цикл повторяется.

Для предотвращения используется внутренний флаг состояния:

  • «изменение инициировано библиотекой»;
  • «изменение внешнее».

Только внешние изменения запускают повторную обработку.


Пример комплексного сценария

const price = new AutoNumeric("#price", {
  decimalPlaces: 2,
  digitGroupSeparator: " ",
  decimalCharacter: ".",
  watchExternalChanges: true
});

// внешняя система обновляет данные
function updateFromServer(value) {
  document.querySelector("#price").value = value;
}

// симуляция обновлений
setTimeout(() => updateFromServer("12345.6"), 1000);
setTimeout(() => updateFromServer("987654.321"), 2000);

Каждое внешнее обновление автоматически приводит к:

  • парсингу строки;
  • нормализации числа;
  • применению форматирования 12 345.60, 987 654.32.

Влияние на производительность

Стоимость включённого наблюдения зависит от:

  • частоты изменений DOM;
  • сложности конфигурации форматирования;
  • количества активных инстансов AutoNumeric.

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


Рекомендации по архитектуре использования

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

  • единый слой обновления через API AutoNumeric;
  • минимизация прямых изменений DOM;
  • контроль всех изменений через централизованный стор.

Такой подход снижает необходимость постоянного DOM-слежения и уменьшает вероятность рассинхронизации состояния.


Поведение при уничтожении экземпляра

При вызове destroy() наблюдение за внешними изменениями прекращается. DOM-элемент возвращается к стандартному поведению input, без автоматического форматирования.

anElement.destroy();

После этого любые изменения input.value больше не обрабатываются библиотекой.