Работа с bitrix:smart.filter
Rus
Eng
Работа с bitrix:smart.filter
Решаю сложные технические задачи для Bitrix и 1С: от аудита чужого кода до разработки сайтов и настройки сложных интеграций с гарантией результата
Рекомендую

Хостинг для сайта

Если выбираете хостинг под проект — советую Timeweb. Современная инфраструктура, широкий выбор тарифов от стартовых до VPS под нагрузку, отзывчивая техподдержка, которая отвечает по существу, а не отписками. Я сам держу на нём часть своих проектов и рекомендую клиентам.

Перейти Партнёрская ссылка. Для вас цена не меняется.

Заменяем checkboxes в bitrix:smart.filter на select

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

В начале вашего шаблона добавьте иконку стрелочки

<svg style="display: none;">
	<symbol version="1.1" id="arrowDown" x="0px" y="0px"
			viewBox="0 0 255 255" style="enable-background:new 0 0 255 255;"
			xml:space="preserve">
		<polygon points="0,63.75 127.5,191.25 255,63.75"/>
	</symbol>
</svg>

В template.php вашего bitrix:smart.filter находим блок выводящий в цикле свойства параметров. У меня это обычно (~534 строка)

default://CHECKBOXES

И для требуемых свойств по условию выставляем новый формат вывода. Например так:

<?if($arItem['CODE'] == 'BRAND'){?>
	<p>Выберите <?=$arItem['NAME']?></p>
	<div class="customSelector" data-attr="<?=$arItem['CODE']?>">
		<div class="customSelectorTitle">
			<?$check = false;
			foreach($arItem["VALUES"] as $val => $ar) {
				if($ar["CHECKED"]){echo $ar['VALUE'];$check = true;}
			}
			if(!$check) {echo $arItem["NAME"];}
			?>
			<svg class="icon"><use xlink:href="#arrowDown" /></svg>
		</div>
		<div class="customSelectorOptions">
			<?foreach($arItem["VALUES"] as $val => $ar) { ?>
				<label class="customSelect <?if ($ar["DISABLED"]){ ?>disabled<? }?>" data-attr="<?echo $ar["VALUE"];?>"><input type="checkbox" name="<?echo $ar["CONTROL_NAME"]?>" id="<?echo $ar["CONTROL_ID"]?>" value="Y" onchange="smartFilter.click(this)" data-attr="<?echo $ar["VALUE"];?>" <?echo $ar["CHECKED"]? 'checked="checked"': ''?> <?if ($ar["DISABLED"]){ ?>disabled<? }?>><?echo $ar["VALUE"];?></label>
			<?}?>
		</div>
	</div>
<?}else{?>
<?foreach($arItem["VALUES"] as $val => $ar):?>
	<label data-role="label_<?=$ar["CONTROL_ID"]?>" class="bx_filter_param_label <? echo $ar["DISABLED"] ? 'disabled': '' ?>" for="<? echo $ar["CONTROL_ID"] ?>">
		<span class="bx_filter_input_checkbox">
			<input
				type="checkbox"
				value="<? echo $ar["HTML_VALUE"] ?>"
				name="<? echo $ar["CONTROL_NAME"] ?>"
				id="<? echo $ar["CONTROL_ID"] ?>"
				<? echo $ar["CHECKED"]? 'checked="checked"': '' ?>
				onclick="smartFilter.click(this)"
			/>
			<span class="bx_filter_param_text" title="<?=$ar["VALUE"];?>"><?=$ar["VALUE"];?><?
			if ($arParams["DISPLAY_ELEMENT_COUNT"] !== "N" && isset($ar["ELEMENT_COUNT"])):
				?> (<span data-role="count_<?=$ar["CONTROL_ID"]?>"><? echo $ar["ELEMENT_COUNT"]; ?></span>)<?
			endif;?></span>
		</span>
	</label>
<?endforeach;?>

Добавляем стили в style.css шаблона

.customSelectorTitle .icon
{-moz-transition: all 0.5s;-webkit-transition: all 0.5s;-o-transition: all 0.5s;-ms-transition: all 0.5s}

.customSelectorTitle {background-color: #fff;border: 1px solid #eee;-ms-align-items: center;align-items: center;padding-left: 12px;font-size: 13px;max-width: 100%;line-height: 50px;cursor: pointer;vertical-align: middle;position: relative;white-space: nowrap;height: 50px;position: relative}
.customSelectorTitle:first-letter {text-transform: uppercase}
.customSelectorTitle .icon{position: absolute;right:10px;top:20px;width: 10px;height: 10px;transform: rotate(0)}
.customSelectorTitle.active .icon{transform: rotate(180deg)}
.customSelect {display: block;width: 100%;cursor: pointer;padding-left: 12px;margin-bottom: 0;line-height: 30px;font-size: 13px}
.customSelect.disabled {color: #fff;background-color: #e3e3e3}
.customSelect:hover {background-color: #e3e3e3}
.customSelect input {display: none;}
.customSelector{position: relative}
.customSelectorOptions {position: absolute;top: 50px;left:0;width: 100%;height: auto;background-color: #fff;border: 1px solid #eee;display: none;z-index: 10;font-size: 16px;}
.main-calculator__card.active{display: flex}

Добавляем jQuery обработчик

(function($) {
	$( document ).ready(function() {
		$('body').on('click','.customSelectorTitle',function(){
			var el = $(this);

			if(el.hasClass('active')){
				el.removeClass('active');
				el.next().stop().slideUp(200);
			}else{
				$('.customSelectorTitle.active ~.customSelectorOptions').slideUp(200);
				$('.customSelectorTitle.active').removeClass('active');

				el.addClass('active');
				el.next().stop().slideDown(200);
			}

		});

		$('.customSelect input').on('change',function(){
			var el = $(this);

			el.parents('.customSelectorOptions').prev().text(el.attr('data-attr')).removeClass('active');
			el.parents('.customSelectorOptions').find('input').not(el).prop('checked', false).val('N');
			el.parents('.customSelectorOptions').stop().slideUp(200);
		});

		$(document).mouseup(function (e){ // событие клика по веб-документу
			var div = $(".customSelector"); // тут указываем ID элемента
			if (!div.is(e.target) // если клик был не по нашему блоку
				&& div.has(e.target).length === 0) { // и не по его дочерним элементам
				$('.customSelectorTitle.active ~.customSelectorOptions').slideUp(200);
				$('.customSelectorTitle.active').removeClass('active');
			}
		});


	});

})(jQuery);

AJAX обновление фильтров bitrix:smart.filter в bitrix:catalog без включенного AJAX_MODE=Y

В файле script.js Вашего шаблона компонента bitrix:smart.filter ищем функцию JCSmartFilter.prototype.postHandler и в ней комментируем строки (~184 строка):

/*if (modef.style.display === 'none')
{
	modef.style.display = 'inline-block';
}*/

Сразу после них добавляем:

$.get(
	result.FILTER_AJAX_URL,
	function (data) {
		$('#catalogBlock').html($(data).find('#catalogBlock').html());
	}
);

history.pushState(null, null, result.FILTER_AJAX_URL);

Ваш каталог должен быть обрамлен в div c id="catalogBlock"

Чтобы сделать вашу пагинацию ajax, то используйте аналогичный код

$(document).on("click", '#catalogBlock .pagination a', function (e) {
	e.preventDefault();
	
	var href=$(this).attr('href');
	
	history.pushState(null, null, href);
	
	$.get(
		href,
		function (data) {
			$('#catalogBlock').html($(data).find('#catalogBlock').html());
		}
	);
});

Источник bitrix ajax обновление списка bitrix:catalog по фильтрам без стандартного ajax включенного AJAX_MODE=Y

Полный листинг скрипта script.js компонента bitrix:smart.filter с включенным ajax из примера выше, кастомным прелоадером и парой исправлений

Прелоадер берем отсюда

Плюс. поскольку у нас чекбоксы, то при выборе второго и далее вариантов bitrix:smart.filter генерирует урл из всех включенных checbox, что нас не устраивает, а потому ищем функцию JCSmartFilter.prototype.click

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

//Обнуляем значения других чекбоксов свойства
var clist = checkbox.closest(".customSelectorOptions").getElementsByTagName("input");
for (var i = 0; i < clist.length; ++i) {
	if(clist[i] !== checkbox){
		clist[i].checked = false;
	}
}

Тогда полный листинг выглядит так:

function JCSmartFilter(ajaxURL, viewMode)
{
	this.ajaxURL = ajaxURL;
	this.form = null;
	this.timer = null;
	this.first = true;
	this.cacheKey = '';
	this.cache = [];
	this.viewMode = viewMode;
}

JCSmartFilter.prototype.keyup = function(input)
{
	if(!!this.timer)
	{
		clearTimeout(this.timer);
	}
	this.timer = setTimeout(BX.delegate(function(){
		this.reload(input);
	}, this), 500);
};

JCSmartFilter.prototype.click = function(checkbox)
{
	if(!!this.timer)
	{
		clearTimeout(this.timer);
	}

	//Обнуляем значения других чекбоксов свойства
	var clist = checkbox.closest(".customSelectorOptions").getElementsByTagName("input");
	for (var i = 0; i < clist.length; ++i) {
		if(clist[i] !== checkbox){
			clist[i].checked = false;
		}
	}

	BX.showWait();

	this.timer = setTimeout(BX.delegate(function(){
		this.reload(checkbox);
	}, this), 1000);
};

JCSmartFilter.prototype.reload = function(input)
{
	if (this.cacheKey !== '')
	{
		//Postprone backend query
		if(!!this.timer)
		{
			clearTimeout(this.timer);
		}
		this.timer = setTimeout(BX.delegate(function(){
			this.reload(input);
		}, this), 1000);
		return;
	}
	this.cacheKey = '|';

	this.position = BX.pos(input, true);
	this.form = BX.findParent(input, {'tag':'form'});
	if (this.form)
	{
		var values = [];
		values[0] = {name: 'ajax', value: 'y'};
		this.gatherInputsValues(values, BX.findChildren(this.form, {'tag': new RegExp('^(input|select)$', 'i')}, true));

		for (var i = 0; i < values.length; i++)
			this.cacheKey += values[i].name + ':' + values[i].value + '|';

		if (this.cache[this.cacheKey])
		{
			this.curFilterinput = input;
			this.postHandler(this.cache[this.cacheKey], true);
		}
		else
		{
			this.curFilterinput = input;
			BX.ajax.loadJSON(
				this.ajaxURL,
				this.values2post(values),
				BX.delegate(this.postHandler, this)
			);
		}
	}
};

JCSmartFilter.prototype.updateItem = function (PID, arItem)
{
	if (arItem.PROPERTY_TYPE === 'N' || arItem.PRICE)
	{
		var trackBar = window['trackBar' + PID];
		if (!trackBar && arItem.ENCODED_ID)
			trackBar = window['trackBar' + arItem.ENCODED_ID];

		if (trackBar && arItem.VALUES)
		{
			if (arItem.VALUES.MIN && arItem.VALUES.MIN.FILTERED_VALUE)
			{
				trackBar.setMinFilteredValue(arItem.VALUES.MIN.FILTERED_VALUE);
			}

			if (arItem.VALUES.MAX && arItem.VALUES.MAX.FILTERED_VALUE)
			{
				trackBar.setMaxFilteredValue(arItem.VALUES.MAX.FILTERED_VALUE);
			}
		}
	}
	else if (arItem.VALUES)
	{
		for (var i in arItem.VALUES)
		{
			if (arItem.VALUES.hasOwnProperty(i))
			{
				var value = arItem.VALUES[i];
				var control = BX(value.CONTROL_ID);

				if (!!control)
				{
					var label = document.querySelector('[data-role="label_'+value.CONTROL_ID+'"]');
					if (value.DISABLED)
					{
						if (label)
							BX.addClass(label, 'disabled');
						else
							BX.addClass(control.parentNode, 'disabled');
					}
					else
					{
						if (label)
							BX.removeClass(label, 'disabled');
						else
							BX.removeClass(control.parentNode, 'disabled');
					}

					if (value.hasOwnProperty('ELEMENT_COUNT'))
					{
						label = document.querySelector('[data-role="count_'+value.CONTROL_ID+'"]');
						if (label)
							label.innerHTML = value.ELEMENT_COUNT;
					}
				}
			}
		}
	}
};

JCSmartFilter.prototype.postHandler = function (result, fromCache)
{
	var hrefFILTER, url, curProp;
	var modef = BX('modef');
	var modef_num = BX('modef_num');

	if (!!result && !!result.ITEMS)
	{
		for(var PID in result.ITEMS)
		{
			if (result.ITEMS.hasOwnProperty(PID))
			{
				this.updateItem(PID, result.ITEMS[PID]);
			}
		}

		if (!!modef && !!modef_num)
		{
			modef_num.innerHTML = result.ELEMENT_COUNT;
			hrefFILTER = BX.findChildren(modef, {tag: 'A'}, true);

			if (result.FILTER_URL && hrefFILTER)
			{
				hrefFILTER[0].href = BX.util.htmlspecialcharsback(result.FILTER_URL);
			}

			if (result.FILTER_AJAX_URL && result.COMPONENT_CONTAINER_ID)
			{
				BX.bind(hrefFILTER[0], 'click', function(e)
				{
					url = BX.util.htmlspecialcharsback(result.FILTER_AJAX_URL);
					BX.ajax.insertToNode(url, result.COMPONENT_CONTAINER_ID);
					return BX.PreventDefault(e);
				});
			}

			if (result.INSTANT_RELOAD && result.COMPONENT_CONTAINER_ID)
			{
				url = BX.util.htmlspecialcharsback(result.FILTER_AJAX_URL);
				BX.ajax.insertToNode(url, result.COMPONENT_CONTAINER_ID);
			}
			else
			{
				/*if (modef.style.display === 'none')
				{
					modef.style.display = 'inline-block';
				}*/

				$.get(
					result.FILTER_AJAX_URL,
					function (data) {
						$('#catalogBlock').html($(data).find('#catalogBlock').html());
						BX.closeWait();
					}
				);

				history.pushState(null, null, result.FILTER_AJAX_URL);

				if (this.viewMode == "vertical")
				{
					curProp = BX.findChild(BX.findParent(this.curFilterinput, {'class':'bx_filter_parameters_box'}), {'class':'bx_filter_container_modef'}, true, false);
					curProp.appendChild(modef);
				}
			}
		}

	}

	if (!fromCache && this.cacheKey !== '')
	{
		this.cache[this.cacheKey] = result;
	}
	this.cacheKey = '';
};

JCSmartFilter.prototype.gatherInputsValues = function (values, elements)
{
	if(elements)
	{
		for(var i = 0; i < elements.length; i++)
		{
			var el = elements[i];
			if (el.disabled || !el.type)
				continue;

			switch(el.type.toLowerCase())
			{
				case 'text':
				case 'textarea':
				case 'password':
				case 'hidden':
				case 'select-one':
					if(el.value.length)
						values[values.length] = {name : el.name, value : el.value};
					break;
				case 'radio':
				case 'checkbox':
					if(el.checked)
						values[values.length] = {name : el.name, value : el.value};
					break;
				case 'select-multiple':
					for (var j = 0; j < el.options.length; j++)
					{
						if (el.options[j].selected)
							values[values.length] = {name : el.name, value : el.options[j].value};
					}
					break;
				default:
					break;
			}
		}
	}
};

JCSmartFilter.prototype.values2post = function (values)
{
	var post = [];
	var current = post;
	var i = 0;

	while(i < values.length)
	{
		var p = values[i].name.indexOf('[');
		if(p == -1)
		{
			current[values[i].name] = values[i].value;
			current = post;
			i++;
		}
		else
		{
			var name = values[i].name.substring(0, p);
			var rest = values[i].name.substring(p+1);
			if(!current[name])
				current[name] = [];

			var pp = rest.indexOf(']');
			if(pp == -1)
			{
				//Error - not balanced brackets
				current = post;
				i++;
			}
			else if(pp == 0)
			{
				//No index specified - so take the next integer
				current = current[name];
				values[i].name = '' + current.length;
			}
			else
			{
				//Now index name becomes and name and we go deeper into the array
				current = current[name];
				values[i].name = rest.substring(0, pp) + rest.substring(pp+1);
			}
		}
	}
	return post;
};

JCSmartFilter.prototype.hideFilterProps = function(element)
{
	var easing;
	var obj = element.parentNode;
	var filterBlock = BX.findChild(obj, {className:"bx_filter_block"}, true, false);

	if(BX.hasClass(obj, "active"))
	{
		easing = new BX.easing({
			duration : 300,
			start : { opacity: 1,  height: filterBlock.offsetHeight },
			finish : { opacity: 0, height:0 },
			transition : BX.easing.transitions.quart,
			step : function(state){
				filterBlock.style.opacity = state.opacity;
				filterBlock.style.height = state.height + "px";
			},
			complete : function() {
				filterBlock.setAttribute("style", "");
				BX.removeClass(obj, "active");
			}
		});
		easing.animate();
	}
	else
	{
		filterBlock.style.display = "block";
		filterBlock.style.opacity = 0;
		filterBlock.style.height = "auto";

		var obj_children_height = filterBlock.offsetHeight;
		filterBlock.style.height = 0;

		easing = new BX.easing({
			duration : 300,
			start : { opacity: 0,  height: 0 },
			finish : { opacity: 1, height: obj_children_height },
			transition : BX.easing.transitions.quart,
			step : function(state){
				filterBlock.style.opacity = state.opacity;
				filterBlock.style.height = state.height + "px";
			},
			complete : function() {
			}
		});
		easing.animate();
		BX.addClass(obj, "active");
	}
};

JCSmartFilter.prototype.showDropDownPopup = function(element, popupId)
{
	var contentNode = element.querySelector('[data-role="dropdownContent"]');
	BX.PopupWindowManager.create("smartFilterDropDown"+popupId, element, {
		autoHide: true,
		offsetLeft: 0,
		offsetTop: 3,
		overlay : false,
		draggable: {restrict:true},
		closeByEsc: true,
		content: contentNode
	}).show();
};

JCSmartFilter.prototype.selectDropDownItem = function(element, controlId)
{
	this.keyup(BX(controlId));

	var wrapContainer = BX.findParent(BX(controlId), {className:"bx_filter_select_container"}, false);

	var currentOption = wrapContainer.querySelector('[data-role="currentOption"]');
	currentOption.innerHTML = element.innerHTML;
	BX.PopupWindowManager.getCurrentPopup().close();
};

BX.namespace("BX.Iblock.SmartFilter");
BX.Iblock.SmartFilter = (function()
{
	var SmartFilter = function(arParams)
	{
		if (typeof arParams === 'object')
		{
			this.leftSlider = BX(arParams.leftSlider);
			this.rightSlider = BX(arParams.rightSlider);
			this.tracker = BX(arParams.tracker);
			this.trackerWrap = BX(arParams.trackerWrap);

			this.minInput = BX(arParams.minInputId);
			this.maxInput = BX(arParams.maxInputId);

			this.minPrice = parseFloat(arParams.minPrice);
			this.maxPrice = parseFloat(arParams.maxPrice);

			this.curMinPrice = parseFloat(arParams.curMinPrice);
			this.curMaxPrice = parseFloat(arParams.curMaxPrice);

			this.fltMinPrice = arParams.fltMinPrice ? parseFloat(arParams.fltMinPrice) : parseFloat(arParams.curMinPrice);
			this.fltMaxPrice = arParams.fltMaxPrice ? parseFloat(arParams.fltMaxPrice) : parseFloat(arParams.curMaxPrice);

			this.precision = arParams.precision || 0;

			this.priceDiff = this.maxPrice - this.minPrice;

			this.leftPercent = 0;
			this.rightPercent = 0;

			this.fltMinPercent = 0;
			this.fltMaxPercent = 0;

			this.colorUnavailableActive = BX(arParams.colorUnavailableActive);//gray
			this.colorAvailableActive = BX(arParams.colorAvailableActive);//blue
			this.colorAvailableInactive = BX(arParams.colorAvailableInactive);//light blue

			this.isTouch = false;

			this.init();

			if ('ontouchstart' in document.documentElement)
			{
				this.isTouch = true;

				BX.bind(this.leftSlider, "touchstart", BX.proxy(function(event){
					this.onMoveLeftSlider(event)
				}, this));

				BX.bind(this.rightSlider, "touchstart", BX.proxy(function(event){
					this.onMoveRightSlider(event)
				}, this));
			}
			else
			{
				BX.bind(this.leftSlider, "mousedown", BX.proxy(function(event){
					this.onMoveLeftSlider(event)
				}, this));

				BX.bind(this.rightSlider, "mousedown", BX.proxy(function(event){
					this.onMoveRightSlider(event)
				}, this));
			}

			BX.bind(this.minInput, "keyup", BX.proxy(function(event){
				this.onInputChange();
			}, this));

			BX.bind(this.maxInput, "keyup", BX.proxy(function(event){
				this.onInputChange();
			}, this));
		}
	};

	SmartFilter.prototype.init = function()
	{
		var priceDiff;

		if (this.curMinPrice > this.minPrice)
		{
			priceDiff = this.curMinPrice - this.minPrice;
			this.leftPercent = (priceDiff*100)/this.priceDiff;

			this.leftSlider.style.left = this.leftPercent + "%";
			this.colorUnavailableActive.style.left = this.leftPercent + "%";
		}

		this.setMinFilteredValue(this.fltMinPrice);

		if (this.curMaxPrice < this.maxPrice)
		{
			priceDiff = this.maxPrice - this.curMaxPrice;
			this.rightPercent = (priceDiff*100)/this.priceDiff;

			this.rightSlider.style.right = this.rightPercent + "%";
			this.colorUnavailableActive.style.right = this.rightPercent + "%";
		}

		this.setMaxFilteredValue(this.fltMaxPrice);
	};

	SmartFilter.prototype.setMinFilteredValue = function (fltMinPrice)
	{
		this.fltMinPrice = parseFloat(fltMinPrice);
		if (this.fltMinPrice >= this.minPrice)
		{
			var priceDiff = this.fltMinPrice - this.minPrice;
			this.fltMinPercent = (priceDiff*100)/this.priceDiff;

			if (this.leftPercent > this.fltMinPercent)
				this.colorAvailableActive.style.left = this.leftPercent + "%";
			else
				this.colorAvailableActive.style.left = this.fltMinPercent + "%";

			this.colorAvailableInactive.style.left = this.fltMinPercent + "%";
		}
		else
		{
			this.colorAvailableActive.style.left = "0%";
			this.colorAvailableInactive.style.left = "0%";
		}
	};

	SmartFilter.prototype.setMaxFilteredValue = function (fltMaxPrice)
	{
		this.fltMaxPrice = parseFloat(fltMaxPrice);
		if (this.fltMaxPrice <= this.maxPrice)
		{
			var priceDiff = this.maxPrice - this.fltMaxPrice;
			this.fltMaxPercent = (priceDiff*100)/this.priceDiff;

			if (this.rightPercent > this.fltMaxPercent)
				this.colorAvailableActive.style.right = this.rightPercent + "%";
			else
				this.colorAvailableActive.style.right = this.fltMaxPercent + "%";

			this.colorAvailableInactive.style.right = this.fltMaxPercent + "%";
		}
		else
		{
			this.colorAvailableActive.style.right = "0%";
			this.colorAvailableInactive.style.right = "0%";
		}
	};

	SmartFilter.prototype.getXCoord = function(elem)
	{
		var box = elem.getBoundingClientRect();
		var body = document.body;
		var docElem = document.documentElement;

		var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;
		var clientLeft = docElem.clientLeft || body.clientLeft || 0;
		var left = box.left + scrollLeft - clientLeft;

		return Math.round(left);
	};

	SmartFilter.prototype.getPageX = function(e)
	{
		e = e || window.event;
		var pageX = null;

		if (this.isTouch && event.targetTouches[0] != null)
		{
			pageX = e.targetTouches[0].pageX;
		}
		else if (e.pageX != null)
		{
			pageX = e.pageX;
		}
		else if (e.clientX != null)
		{
			var html = document.documentElement;
			var body = document.body;

			pageX = e.clientX + (html.scrollLeft || body && body.scrollLeft || 0);
			pageX -= html.clientLeft || 0;
		}

		return pageX;
	};

	SmartFilter.prototype.recountMinPrice = function()
	{
		var newMinPrice = (this.priceDiff*this.leftPercent)/100;
		newMinPrice = (this.minPrice + newMinPrice).toFixed(this.precision);

		if (newMinPrice != this.minPrice)
			this.minInput.value = newMinPrice;
		else
			this.minInput.value = "";
		smartFilter.keyup(this.minInput);
	};

	SmartFilter.prototype.recountMaxPrice = function()
	{
		var newMaxPrice = (this.priceDiff*this.rightPercent)/100;
		newMaxPrice = (this.maxPrice - newMaxPrice).toFixed(this.precision);

		if (newMaxPrice != this.maxPrice)
			this.maxInput.value = newMaxPrice;
		else
			this.maxInput.value = "";
		smartFilter.keyup(this.maxInput);
	};

	SmartFilter.prototype.onInputChange = function ()
	{
		var priceDiff;
		if (this.minInput.value)
		{
			var leftInputValue = this.minInput.value;
			if (leftInputValue < this.minPrice)
				leftInputValue = this.minPrice;

			if (leftInputValue > this.maxPrice)
				leftInputValue = this.maxPrice;

			priceDiff = leftInputValue - this.minPrice;
			this.leftPercent = (priceDiff*100)/this.priceDiff;

			this.makeLeftSliderMove(false);
		}

		if (this.maxInput.value)
		{
			var rightInputValue = this.maxInput.value;
			if (rightInputValue < this.minPrice)
				rightInputValue = this.minPrice;

			if (rightInputValue > this.maxPrice)
				rightInputValue = this.maxPrice;

			priceDiff = this.maxPrice - rightInputValue;
			this.rightPercent = (priceDiff*100)/this.priceDiff;

			this.makeRightSliderMove(false);
		}
	};

	SmartFilter.prototype.makeLeftSliderMove = function(recountPrice)
	{
		recountPrice = (recountPrice === false) ? false : true;

		this.leftSlider.style.left = this.leftPercent + "%";
		this.colorUnavailableActive.style.left = this.leftPercent + "%";

		var areBothSlidersMoving = false;
		if (this.leftPercent + this.rightPercent >= 100)
		{
			areBothSlidersMoving = true;
			this.rightPercent = 100 - this.leftPercent;
			this.rightSlider.style.right = this.rightPercent + "%";
			this.colorUnavailableActive.style.right = this.rightPercent + "%";
		}

		if (this.leftPercent >= this.fltMinPercent && this.leftPercent <= (100-this.fltMaxPercent))
		{
			this.colorAvailableActive.style.left = this.leftPercent + "%";
			if (areBothSlidersMoving)
			{
				this.colorAvailableActive.style.right = 100 - this.leftPercent + "%";
			}
		}
		else if(this.leftPercent <= this.fltMinPercent)
		{
			this.colorAvailableActive.style.left = this.fltMinPercent + "%";
			if (areBothSlidersMoving)
			{
				this.colorAvailableActive.style.right = 100 - this.fltMinPercent + "%";
			}
		}
		else if(this.leftPercent >= this.fltMaxPercent)
		{
			this.colorAvailableActive.style.left = 100-this.fltMaxPercent + "%";
			if (areBothSlidersMoving)
			{
				this.colorAvailableActive.style.right = this.fltMaxPercent + "%";
			}
		}

		if (recountPrice)
		{
			this.recountMinPrice();
			if (areBothSlidersMoving)
				this.recountMaxPrice();
		}
	};

	SmartFilter.prototype.countNewLeft = function(event)
	{
		var pageX = this.getPageX(event);

		var trackerXCoord = this.getXCoord(this.trackerWrap);
		var rightEdge = this.trackerWrap.offsetWidth;

		var newLeft = pageX - trackerXCoord;

		if (newLeft < 0)
			newLeft = 0;
		else if (newLeft > rightEdge)
			newLeft = rightEdge;

		return newLeft;
	};

	SmartFilter.prototype.onMoveLeftSlider = function(e)
	{
		if (!this.isTouch)
		{
			this.leftSlider.ondragstart = function() {
				return false;
			};
		}

		if (!this.isTouch)
		{
			document.onmousemove = BX.proxy(function(event) {
				this.leftPercent = ((this.countNewLeft(event)*100)/this.trackerWrap.offsetWidth);
				this.makeLeftSliderMove();
			}, this);

			document.onmouseup = function() {
				document.onmousemove = document.onmouseup = null;
			};
		}
		else
		{
			document.ontouchmove = BX.proxy(function(event) {
				this.leftPercent = ((this.countNewLeft(event)*100)/this.trackerWrap.offsetWidth);
				this.makeLeftSliderMove();
			}, this);

			document.ontouchend = function() {
				document.ontouchmove = document.touchend = null;
			};
		}

		return false;
	};

	SmartFilter.prototype.makeRightSliderMove = function(recountPrice)
	{
		recountPrice = (recountPrice === false) ? false : true;

		this.rightSlider.style.right = this.rightPercent + "%";
		this.colorUnavailableActive.style.right = this.rightPercent + "%";

		var areBothSlidersMoving = false;
		if (this.leftPercent + this.rightPercent >= 100)
		{
			areBothSlidersMoving = true;
			this.leftPercent = 100 - this.rightPercent;
			this.leftSlider.style.left = this.leftPercent + "%";
			this.colorUnavailableActive.style.left = this.leftPercent + "%";
		}

		if ((100-this.rightPercent) >= this.fltMinPercent && this.rightPercent >= this.fltMaxPercent)
		{
			this.colorAvailableActive.style.right = this.rightPercent + "%";
			if (areBothSlidersMoving)
			{
				this.colorAvailableActive.style.left = 100 - this.rightPercent + "%";
			}
		}
		else if(this.rightPercent <= this.fltMaxPercent)
		{
			this.colorAvailableActive.style.right = this.fltMaxPercent + "%";
			if (areBothSlidersMoving)
			{
				this.colorAvailableActive.style.left = 100 - this.fltMaxPercent + "%";
			}
		}
		else if((100-this.rightPercent) <= this.fltMinPercent)
		{
			this.colorAvailableActive.style.right = 100-this.fltMinPercent + "%";
			if (areBothSlidersMoving)
			{
				this.colorAvailableActive.style.left = this.fltMinPercent + "%";
			}
		}

		if (recountPrice)
		{
			this.recountMaxPrice();
			if (areBothSlidersMoving)
				this.recountMinPrice();
		}
	};

	SmartFilter.prototype.onMoveRightSlider = function(e)
	{
		if (!this.isTouch)
		{
			this.rightSlider.ondragstart = function() {
				return false;
			};
		}

		if (!this.isTouch)
		{
			document.onmousemove = BX.proxy(function(event) {
				this.rightPercent = 100-(((this.countNewLeft(event))*100)/(this.trackerWrap.offsetWidth));
				this.makeRightSliderMove();
			}, this);

			document.onmouseup = function() {
				document.onmousemove = document.onmouseup = null;
			};
		}
		else
		{
			document.ontouchmove = BX.proxy(function(event) {
				this.rightPercent = 100-(((this.countNewLeft(event))*100)/(this.trackerWrap.offsetWidth));
				this.makeRightSliderMove();
			}, this);

			document.ontouchend = function() {
				document.ontouchmove = document.ontouchend = null;
			};
		}

		return false;
	};

	return SmartFilter;
})();

(function($) {
	$( document ).ready(function() {
		$('body').on('click','.customSelectorTitle',function(){
			var el = $(this);

			if(el.hasClass('active')){
				el.removeClass('active');
				el.next().stop().slideUp(200);
			}else{
				$('.customSelectorTitle.active ~.customSelectorOptions').slideUp(200);
				$('.customSelectorTitle.active').removeClass('active');

				el.addClass('active');
				el.next().stop().slideDown(200);
			}

		});

		$('.customSelect input').on('change',function(){
			var el = $(this);

			el.parents('.customSelectorOptions').prev().text(el.attr('data-attr')).removeClass('active');
			el.parents('.customSelectorOptions').find('input').not(el).prop('checked', false).val('N');
			el.parents('.customSelectorOptions').stop().slideUp(200);
		});

		$(document).mouseup(function (e){ // событие клика по веб-документу
			var div = $(".customSelector"); // тут указываем ID элемента
			if (!div.is(e.target) // если клик был не по нашему блоку
				&& div.has(e.target).length === 0) { // и не по его дочерним элементам
				$('.customSelectorTitle.active ~.customSelectorOptions').slideUp(200);
				$('.customSelectorTitle.active').removeClass('active');
			}
		});


	});

})(jQuery);

var lastWait = [];

/* non-xhr loadings */
BX.showWait = function (node, msg)
{
	node = BX(node) || document.body || document.documentElement;
	msg = msg || BX.message('JS_CORE_LOADING');

	var container_id = node.id || Math.random();

	var obMsg = node.bxmsg = document.body.appendChild(BX.create('DIV', {
		props: {
			id: 'wait_' + container_id,
			className: 'bx-core-waitwindow'
		},
		text: msg
	}));

	setTimeout(BX.delegate(_adjustWait, node), 10);

	$('.pWrap').show();
	lastWait[lastWait.length] = obMsg;
	return obMsg;
};

BX.closeWait = function (node, obMsg)
{
	$('.pWrap').hide();
	if (node && !obMsg)
		obMsg = node.bxmsg;
	if (node && !obMsg && BX.hasClass(node, 'bx-core-waitwindow'))
		obMsg = node;
	if (node && !obMsg)
		obMsg = BX('wait_' + node.id);
	if (!obMsg)
		obMsg = lastWait.pop();

	if (obMsg && obMsg.parentNode)
	{
		for (var i = 0, len = lastWait.length; i < len; i++)
		{
			if (obMsg == lastWait[i])
			{
				lastWait = BX.util.deleteFromArray(lastWait, i);
				break;
			}
		}

		obMsg.parentNode.removeChild(obMsg);
		if (node)
			node.bxmsg = null;
		BX.cleanNode(obMsg, true);
	}
};

function _adjustWait()
{
	if (!this.bxmsg)
		return;

	var arContainerPos = BX.pos(this),
		div_top = arContainerPos.top;

	if (div_top < BX.GetDocElement().scrollTop)
		div_top = BX.GetDocElement().scrollTop + 5;

	this.bxmsg.style.top = (div_top + 5) + 'px';

	if (this == BX.GetDocElement())
	{
		this.bxmsg.style.right = '5px';
	}
	else
	{
		this.bxmsg.style.left = (arContainerPos.right - this.bxmsg.offsetWidth - 5) + 'px';
	}
}

Ajax фильтрация catalog.smart.filter при submit формы

Идем в script.js вашего шаблона фильтра и перед строкой if (result.INSTANT_RELOAD && result.COMPONENT_CONTAINER_ID) вставляем

if (result.FILTER_AJAX_URL && result.COMPONENT_CONTAINER_ID)
{
	BX.bind(document.querySelector('#set_filter'), 'click', function(e) //где set_filter это id вашей кнопки submit
	{
		url = BX.util.htmlspecialcharsback(result.FILTER_AJAX_URL);
		BX.ajax.insertToNode(url, result.COMPONENT_CONTAINER_ID);
		return BX.PreventDefault(e);
	});
}

Находим функцию JCSmartFilter.prototype.bindUrlToButton и комментируем строки:

BX.bind(button, 'click', proxy(url, function(url)
{
	window.location.href = url;
	return false;
}));

Фильтруем каталог по свойству типа список

Размещаем код перед вызовом bitrix:catalog.section

//Фильтруем каталог по свойству типа список
if ($sGetSort = $request->getQuery("set")) {
	switch($sGetSort) {
		case '5':
			$arrFilter['=PROPERTY_SET'] = '193';
			break;
		case '10':
			$arrFilter['=PROPERTY_SET'] = '194';
			break;
	}
}
//Где PROPERTY_SET - код фильтруемого свойства
//, а 193\194 - ID фильтруемых свойств

Выводим фильтр по параметру

Размещаем в файле result_modifier.php дополнительный массив с нашим параметром. Решение "грязное", но рабочее

$arResult['ITEMS'][778] = [
    'ID' => 778,
    'IBLOCK_ID' => 9,
    'CODE' => 'SET',
    'NAME' => 'Сет',
    'PROPERTY_TYPE' => 'L',
    'DISPLAY_TYPE' => 'P',
    'DISPLAY_EXPANDED' => 'N',
    'VALUES' => [
            '779' => [
                'CONTROL_ID' => 'set_3390377895',
                'CONTROL_NAME' => 'set_3390377895',
                'CONTROL_NAME_ALT' => 'set',
                'HTML_VALUE_ALT' => '5',
                'HTML_VALUE' => 'Y',
                'VALUE' => '5 товаров в наборе',
                'SORT' => '100',
                'UPPER' => '5 ТОВАРОВ В НАБОРЕ',
                'URL_ID' => rand(32),
            ],
            '780' => [
                'CONTROL_ID' => 'set_778_3390377895',
                'CONTROL_NAME' => 'set_3390377895',
                'CONTROL_NAME_ALT' => 'set',
                'HTML_VALUE_ALT' => '10',
                'HTML_VALUE' => 'Y',
                'VALUE' => '10 товаров в наборе',
                'SORT' => '200',
                'UPPER' => '10 ТОВАРОВ В НАБОРЕ',
                'URL_ID' => rand(32),
            ],
    ]
];
Александр Тихий
Автор статьи

Александр Тихий

Fullstack-разработчик · 1С-Битрикс

Разрабатываю и развиваю интернет-магазины и корпоративные порталы на 1С-Битрикс. Интеграции с 1С, highload-нагрузки, безопасность по 152-ФЗ.


Комментарии

Комментариев еще нет, Вы можете стать первым кто его оставит

Оставьте комментарий

На сайте используется система премодерирования комментариев, поэтому ваше сообщение будет опубликовано лишь после одобрения модератором

Вы отвечаете на комментарий пользователя

Отправить

ОБРАТНАЯ СВЯЗЬ

Напишите мне

Напишите мне, чтобы обсудить задачу. Работаю удаленно, официально (самозанятый), стоимость часа — 1800 ₽, в день могу уделять проекту 3–4 часа. Отвечаю быстро, консультация бесплатная.

Во время отправки произошла ошибка, пожалуйста попробуйте еще раз через некоторое время
Сообщение отправлено успешно

Телефоны

+7(993) 007-18-96

Email

info@tichiy.ru

Адрес

Россия, г. Москва

Отправляя форму Вы автоматически подтверждаете, что ознакомились и принимаете Политику конфиденциальности сайта