В JavaScript-ядре Bitrix Framework есть пара лаконичных, но невероятно полезных методов — BX.denyEvent()
и BX.allowEvent()
. С их помощью можно временно отключать и снова включать обработчики конкретного события на конкретном DOM-элементе. Это особенно удобно, когда нужно предотвратить «дребезг» событий, циклические вызовы или непреднамеренное срабатывание логики во время сложных UI-операций.

Важно: сейчас методы влияют только на обработчики, назначенные через свойство
element['on' + event]
(то есть черезelem.onclick = …
и др.). Слушатели, добавленныеBX.bind
,addEventListener
или jQuery, не блокируются.
Сигнатуры методов
/**
* Запрещает указанное событие только для данного узла.
* @param {HTMLElement} node – DOM-элемент-адресат
* @param {String} type – имя события (без «on»)
*/
BX.denyEvent(node, type);
/**
* Снимает запрет на событие, введённый BX.denyEvent().
* Параметры аналогичны первому методу.
*/
BX.allowEvent(node, type);
Когда это нужно
Ситуация | Что даёт deny/allow |
---|---|
Кнопка «Сохранить» посылает AJAX-запрос, и пользователь кликает по ней многократно | На время запроса блокируем click , исключая повторную отправку |
Слайдер сам изменяет scrollLeft , а «scroll» триггерит тяжёлые вычисления |
Внутри анимации запрещаем scroll , затем включаем обратно |
Массовое заполнение полей формы через скрипт | Отрубаем change , чтобы не запускать валидацию на каждое поле |
Практические примеры
1. Защита кнопки от «залипания» кликов
<button id="saveBtn" class="ui-btn ui-btn-primary">Сохранить</button>
<script>
BX.ready(function () {
const btn = document.getElementById('saveBtn');
// Бизнес-логика по «нажатию»
btn.onclick = function handleSave () {
// имитация долгого запроса
BX.ajax.runAction('demo:storage.save', { data: collectFormData() })
.then(showSuccess)
.catch(showError)
.finally(unlock);
};
// Вешаем «щелчок» исключительно во внешний код,
// а внутри временно запрещаем прежний onclick
BX.bind(btn, 'click', function () {
lock();
btn.onclick(); // вызываем основной обработчик вручную
});
function lock () {
BX.denyEvent(btn, 'click'); // отключили
btn.classList.add('ui-btn-wait');
}
function unlock () {
BX.allowEvent(btn, 'click'); // включили
btn.classList.remove('ui-btn-wait');
}
function showSuccess () { BX.UI.Notification.Center.notify({content: 'Сохранено!'}); }
function showError () { BX.UI.Notification.Center.notify({content: 'Ошибка сохранения'}); }
});
</script>
Особенности:
BX.bind
ставит отдельный слушательaddEventListener
, поэтому не попадает под запрет.- Запрещаем только «нативный»
onclick
, предотвращая повторную отправку данных.
2. Анимация списка без «дребезга» scroll
<div id="gallery" class="gallery">
<!-- длинная горизонтальная лента -->
</div>
<script>
BX.ready(function () {
const box = document.getElementById('gallery');
box.onscroll = throttle(highlightVisibleSlide, 100); // тяжёлый код
function moveTo(position) {
BX.denyEvent(box, 'scroll'); // стоп heavy-scroll
BX.easing({
duration : 500,
start : {x: box.scrollLeft},
finish : {x: position},
transition: BX.easing.makeEaseOut(BX.easing.transitions.quad),
step: state => box.scrollLeft = state.x,
complete: () => BX.allowEvent(box, 'scroll')
}).animate();
}
// пример перехода
BX.bindDelegate(document, 'click', {className: 'js-slide-link'}, e => {
const targetPos = Number(e.target.dataset.offset);
moveTo(targetPos);
});
});
</script>
Здесь мы:
- На время анимации полностью «глушим»
scroll
. - После окончания плавно включаем обработчик обратно, чтобы подсветка слайдов возобновилась.
3. Массовый апдейт формы без каскада change
<script>
BX.ready(function () {
const form = document.forms.namedItem('dealEdit');
const inputs = Array.from(form.querySelectorAll('[data-auto-fill]'));
// Каждый input хранит в onChange валидацию
inputs.forEach(input => {
input.onchange = () => validateField(input);
});
// Массовое заполнение
function autoFillDemoData () {
// временно вырубаем change у каждого поля
inputs.forEach(i => BX.denyEvent(i, 'change'));
// симуляция вставки данных
BX.Promise.all(inputs.map(i => {
i.value = getMock(i.name);
return BX.Promise.resolve();
})).then(() => {
// возвращаем change
inputs.forEach(i => BX.allowEvent(i, 'change'));
// финальная полная валидация
validateForm(form);
});
}
BX.bind(document.getElementById('demoFill'), 'click', autoFillDemoData);
});
</script>
Советы и подводные камни
- Убедитесь, что используете
element.on<Event>
. Если обработчик назначен черезBX.bind
или сторонние библиотеки, запрет не подействует. - Соблюдайте симметрию — всегда вызывайте
BX.allowEvent
послеBX.denyEvent
, иначе пользователь может «зависнуть» без нужной реакции интерфейса. - Имена событий указываются без префикса
on
:'click'
,'scroll'
,'change'
. - Исключайте вложенные блокировки: если в разных частях кода применяется
denyEvent
к одному элементу, продумайте порядок включения обратно, чтобы не снять запрет преждевременно. - Для частого запрета/разрешения событий рассмотрите дебаунс или троттлинг вместо полного отключения. Это даст тот же эффект без риска забыть вернуть обработчик.
Заключение
BX.denyEvent
и BX.allowEvent
— точечный, но мощный инструмент фронтенд-разработчика в 1С-Битрикс. Они позволяют управлять жизненным циклом событий так, чтобы UI оставался отзывчивым, а логика — предсказуемой. Используйте их, когда нужно временно приостановить реакцию интерфейса, и обязательно возвращайте события в исходное состояние — тогда ваш код будет не только удобочитаемым, но и безопасным для пользователя.