Как стать автором
Обновить

Комментарии 28

Ммм, поиск в нескольких значениях как бы не интересен, а вот если значений сотни, то тогда уже стоит делать автодополнение, которые похоже, но обычно имеет серверную часть что бы не грузить весь список сразу.
или подгружать список
Навскидку приходит ещё один вариант:
1. Все option пометить классом 'searchable'.
2. Поиск производить по всем option с классом 'searchable'
3. Все option не соответствующие условию отбора помещать в другой select на котором установлено display:none. Все option соответствующие условию отбора помещать в исходный select.

Вроде бы должно работать. Завтра попробую реализовать в коде… сегодня уже поздновато.
Второе что приходит в голову — Wott прав, и стоило бы сделать загрузку данных аяксом с поиском на сервере. Но ситуации бывают всякие, и если так прижало что надо реализовать все на клиенте, то так же стоит обратить внимание на jQuery.data(). Сохраняем все в массиве, очищаем select полностью, обходим сохранённый массив при поиске и наполняем select. Это пожалуй самый правильный вариант. Вечером попробую накидать и этот вариант.
Главное, чтоб это делать по событию onload — в смысле зачистку всего селекта. Тогда можно не кастрировать браузеры без javascript-а
По мне так намудрили, если делать автокомплит то делать его уже реализуя селект на дом элементах типо div ul a. ну а так по моему в селекте и так можно быстро перескочить на нужную букву.

А span внутри select я вам скажу может вызвать неизвестные и не понятные баги, в частности при обновлении браузеров или в каких-то малоизвестных браузерах. Не валидно это значит то что не прописано в стандарте то есть создатели браузеров на это не рассчитывают, и при обновлении браузера или в каком-то сафари юзер возможно не сможет работать с вашим селектом.
Дефолтный поиск в списке работает от начала строки. Тут можно искать по всей строке.
Можно jNice использовать. Но, при большом количестве записей — да, лучше иметь серверную часть.
Где регулярка, я бы вместо $(this).val() написал бы просто this.value
Там проблема гораздо интереснее: а если this.value примет значение "[A-Z]*" мне найдет что? Правильно…
а вы не пробовали .detach() и .append() для манипулирования элементами select-а?
я как раз это и предложил, просто реализовать пока не получается, со временем напряженка.
Но на самом деле такие манипуляции будут тяжелее чем сохранить весь список при помощи jQuery.data() и искать уже там.
может я не совсем улавливаю задачу…
Можно же сохранить данные сразу в js массив. Искать по нему. Заполнять select данными из массива согласно критериям.
Я думаю это будет быстрее чем шариться по DOM-у.
все можно :)

Я отвечал в контексте текущей задачи. Здесь проблема скорее всего в том что задача неверно сформулирована. ИМХО самый верный вариант предложили в первом же комментарии.
Варианты с манипуляциями DOM я обдумывал просто ради спортивного интереса :)
Ради интереса реализовал вариант с .detach() и .appendTo().
Поменял только скрипт поиска, и добавил один select на страницу:
<select size="10" id="hidden_list" style="display:none;">
	</select>


код скрипта:
$('#searchInput').bind('keyup', function() {
    var q = new RegExp($(this).val(), 'ig');
	$('#list, #hidden_list').find('option').each(function(){
		if ($(this).text().match(q)){
			$(this).parent('#hidden_list').size() ? $(this).detach().appendTo('#list') : null;
		}
		else{
			$(this).parent('#list').size() ? $(this).detach().appendTo('#hidden_list') : null;
		}	
	});
});


Рабочий пример можно посмотреть здесь.
Так гораздо лучше, точнее решается проблема с google chrome, который по методу автора топика оставлял в select выделенным убранный элемент, если к нему не прикасался пользователь. Теперь выделенный и тот который выглядит выделенным в хроме одинаковые.
Мой поиск по селекту занимает строк 300, с кэшированием и всякими прибаутками. Зачем регулярку юзать? indexOf разве не быстрее? Да и все обязательно нужно обернуть в $, так богаче смотрится :)
как минимум indexOf регистрозависим
Скрывать элементы можно, если вместо select использовать например ul/li, который к тому же стилизуется как угодно. И вы наркоман какой-то, вместо того, чтобы посмотреть интерфейс HTMLSelectElement и использовать нормальные DOM интерфейсы, вроде коллекции options, методов add()/remove(), вы какими-то странными обходными путями выдергиваете отдельные option, и каждый обертываете в jQuery, только ради того, чтобы вызвать у него метод text(). Треш и ужас.

Я никому не советую использовать этот метод, а написать все нормально.
bind('keyup' — и right click -> paste идёт лесом.
onchange — и тоже идёт лесом, пока фокус не уйдёт в другое место.
Поэтому надо просто по таймауту раз в 100мс или больше сравнивать #searchInput с oldSearchInput
А если оба?
Оба тоже не отследят это событие.
Может быть я конечно ошибаюсь, но нет такого события, которое отследит изменение input без смены фокуса и умеет отслеживать операцию paste, а также какую-нибудь автоподставновку браузера.
А не проще и удобней все значения селектов держать в массивчике и исходя из поиска добавлять в селект только нужные элементы (option) из массива?
Как-то так. По мне так компактней и удобней =)
var arrElements = [...];
var select = $('#list');
$('#searchInput').bind('keyup', function() {
    for (var i = 0; i < arrElements.length; i ++) {
        if (-1 !== arrElements[i].indexOf(q)) {
            var option = $('<option>').html(arrElements[i]).val(arrElements[i]);
            select.append( option );
        }
    } 
});
А где добавление в массивчик?
Там же где в статье добавление в селект ;) Его можно элементарно сгенерить на сервере в JSON и на клиенте уже появится валидный массив.
В таком случае, как минимум надо дописать удаление из селекта.
А пока решение Silver_Clash лучшее.
select.get(0).elements.length = 0; // очистка селекта;
А чем лучше решение Silver_Clash? Оно как минимум в 3 раза накладней чем мое (поиск в дом, отделение элемента от дом, лишнее добавление элемента в дом)
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории