Фильтрация элементов в cuSel

    image

    На одном из сайтов, который я имею честь обслуживать, для кастомизации селекта используется замечательный jQuery-плагин cuSel. Он удобен тем, что достаточно прост в настройке и позволяет кастомизировать даже полосу прокрутки.
    Но иногда случается так, что список элементов может быть очень большим. И быстро найти нужный пункт не так просто.

    Однажды мне поступила задача реализовать возможность ввода текста и фильтрации элементов по первым буквам. Список состоял из названий городов Украины и был достаточно длинным. Поскольку в самом плагине данная возможность отсутствовала, а отказываться от красивого селекта как и я так и заказчик не хотел, было принято решение внести небольшие доработки в код скрипта.

    Сегодня я постараюсь повторить все это вместе с вами. Для этого возьмем демонстрационный пример со странички плагина. В архиве содержаться все необходимые библиотеки и стили. На странице index.html автор подготовил несколько примеров подключения и использования плагина. Давайте добавим фильтрацию для первого селекта, в котором содержится список стран.

    Для ввода текста мы будем использовать прозрачное текстовое поле, которое по клику будет налаживаться верхним слоем на селект. Добавим для этого поля соответствующий css-класс в файл css/cusel.css и установим такие же размеры для блока, в котором отображается текст выбранного элемента списка.

    .cusel .search-field {
    	position: absolute;
    	outline:0;
    	border: 0;
    	background: transparent;
    	display:none;
    }
    .cusel .search-field, .cuselText {
    	width: 144px;
    	height: 20px;
    	line-height:20px;
    	padding: 3px 30px 3px 6px;
    }
    


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

    		<select class="sel80 filtering" id="country" name="country" tabindex="2">
    


    Откроем файл js/cusel.js и добавим следующий код в функцию cuselEvents.

    jQuery(".cusel").each(function () {
    		var itv;
    		var elm = $(this);
    		if (elm.hasClass("filtering") && elm.find(".search-field").length == 0) {
    			var f = $("<input type='text' />")
    			f.addClass("search-field");
    			f.keydown(function () {
    				clearInterval(itv);
    				var list = elm.find(".cusel-scroll-pane > span");
    				itv = setInterval(function () {
    					list.each(function () {
    						var item = $(this);
    						item.show();
    						if (item.text().toLowerCase().indexOf(f.val().toLowerCase()) != 0)
    							item.hide();
    					});
    					var d = elm.find(".cusel-scroll-pane").eq(0).attr("id");
    					jQuery("#" + d)[0].scrollTo(0);
    					clearInterval(itv);
    				}, 100);
    			});
    			f.click(function () {
    				$(this).val('').hide();
    				elm.focus();
    			});
    			elm.append(f);
    		}
    	});
    


    Что делает данный код? Находит на странице все элементы с классом «cusel» т.к. именно этот класс используется в стилизированных селектах. Далее, если для селекта указан класс «filtering» и он не имеет дочерний элемент с классом «search-field» (наше поле для ввода текста), то такое поле создается и на него вешается обработчик события. Обработчик, по каждому нажатию клавиш в поле, находит пункты в списке, текст которых не соответствует тексту в поле и просто скрывает их.

    Теперь нам нужно сделать так, чтобы по клику на селекте над ним появлялось наше прозрачное поле. Для этого в той же функцие cuselEvents найдем обработчик события «click». В нем необходимо отыскать часть кода помеченную комментарием автора «если кликнули по самому селекту (текст)» и изменить следующим образом.

    /* если кликнули по самому селекту (текст) */
    		if((clickedClass.indexOf("cuselText")!=-1 || clickedClass.indexOf("cuselFrameRight")!=-1) && clicked.parent().prop("class").indexOf("classDisCusel")==-1)
    		{
    			var cuselWrap = clicked.parent().find(".cusel-scroll-wrap").eq(0);
    
    			var parent = clicked.parents(".cusel");
    			if (parent.hasClass("filtering")) {
    				var txt = parent.children(".cuselText");
    				var sf = parent.children(".search-field");
    				if(sf.is(":hidden")) {
    					txt.text("");
    					sf.show().focus();
    				}
    				else {
    					txt.text(parent.find(".cuselActive").eq(0).text());
    					sf.val("").hide();
    				}
    			}
    
    			/* если выпадающее меню скрыто - показываем */
    			cuselShowList(cuselWrap);
    		}
    


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

    Теперь сделаем, чтобы при выборе элемента в списке, поле наоборот скрывалось. Ниже найдите блок помеченный комментарием автора «если выбрали позицию в списке» и добавьте туда следующий код

    			else if(clicked.is(".cusel-scroll-wrap span") && clickedClass.indexOf("cuselActive")==-1) {
    
    		         var parent = clicked.parents(".cusel");
    		         if (parent.hasClass("filtering")) {
    		            parent.children(".search-field").val('').hide();
    		            parent.find(".cusel-scroll-pane > span").show();
    		         }
    
                             //оригинальный код
    			}
    


    Как видно при этом мы делаем видимыми скрытые при фильтрации элементы списка.

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

    /*
    		скрываем раскрытые списки, если кликнули вне списка
    		*/
    		else {
    			var wrap = jQuery(".cusel-scroll-wrap");
    			var parent = wrap.parents(".cusel");
    
    			parent.each(function () {
    				var elm = $(this);
    				if (elm.hasClass("filtering")) {
    					elm.find(".cuselText").text(elm.find(".cuselActive").eq(0).text());
    					elm.find(".search-field").val('').hide();
    					elm.find(".cusel-scroll-pane > span").show();
    				}
    			});
    
    			wrap.hide();
    			parent.removeClass("cuselOpen")
    		}
    


    И теперь последний штрих. В самом конце функции cuselEvents вы найдете кусок кода помеченный следующим комментарием

            /*
    	функция отбора по нажатым символам (от Alexey Choporov)
    	отбор идет пока пауза между нажатиями сиволов не будет больше 0.5 сек
    	keypress нужен для отлова символа нажатой клавиш
           */
    


    Функция Алексея подбирает подходящее значение по первой букве. Мы же реализовываем возможность отбора по нескольким буквам. Поэтому во избежание конфликтов код Алексея необходимо закомментировать.

    Исходники

    • –1
    • 7,6k
    • 8
    Поделиться публикацией

    Похожие публикации

    Комментарии 8
      0
      Для схожих целей использую select2. Фильтрация встроенная, но для одиночных select'ов на мой взгляд менее удобная, чем предложенный вами вариант. В закладки.

      P.S. Очень не хватает демо.
        0
        Спасибо за наводку, как раз искал подобное.
          0
          в cuSel вся фишка в стилизации скроллбара, поэтому в ряде случаев подходит только он
          +1
          А какая логика в
          jQuery(".cusel")
          

          если можно было сразу выбрать только нужные(с классом filtering)
          jQuery(".cusel.filtering")
          

          Имею в виду зачем создавать неиспользуемые переменные?
            0
            Вы правы. Вероятно для чего-то сперва сделал именно так. А потом пропустил оптимизировать.
            +1
            Не рекомендую использовать cuSel по 2 причинам:
            — самая последняя версия jquery которая им поддерживается 1.6.4
            — лицензия — её просто нет!
              0
              Скрытый текст
              Почему

              jQuery(".cusel").each(function () {
              ..
                      if (elm.hasClass("filtering")...
              

              а не

              jQuery(".cusel.filtering")...
              

              быстрее же должно быть.


              Ну и не плохо было бы отправить это разработчику плагина cuSel.

              UPD: не успел, уже ответили
                0
                Есть прекрасный Chosen

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое