Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 05.05.2013, 16:54
Интересующийся
Отправить личное сообщение для TrogWar Посмотреть профиль Найти все сообщения от TrogWar
 
Регистрация: 15.04.2012
Сообщений: 12

Конъюнкция из нескольких filter()
Доброго времени суток!

Есть фильтр товаров по разным категориям и сам список товаров. Все данные хранятся в data-аттрибутах.
Разметка:
<!-- Чекбоксы -->
<input type="checkbox" data-type="foo" data-foo="foo_item1">
<input type="checkbox" data-type="foo" data-foo="foo_item2">
...
<input type="checkbox" data-type="bar" data-bar="bar_item1">
<input type="checkbox" data-type="bar" data-bar="bar_item2">

<!-- Товары -->
<div class="item" data-foo="foo_item1" data-bar="bar_item1" >
<div class="item" data-foo="foo_item2" data-bar="bar_item2" >
...


В фильтре две категории: "foo" и "bar". Мне нужно чтобы при выборе чекбоксов из обоих типов подсвечивалось только то, что удовлетворяет двум условиям одновременно. Это было несложно:
function getFilteredItems(type) {
  // сомнительный момент – сбор выделенных типов (нужен ли он?)
  var checkedTypes = $(':checked').map(function(i,ch){
    return $(ch).data(type);
  });
  // сбор узлов для подсветки
  var resultItems = $('.item').filter(function(){
    // кэшируем текущий элемент чтобы передать в другой метод
    var item = $(this);
    // Возвращает true если хотя бы один элемент true
    return checkedTypes.some(function(typeItem){
      // проверка на совпадение data-аттрибута товара с data-аттрибутом чекбокса
      return typeItem==item.data(type);
    });
  });
  return resultItems;
}

$('#filter').find(':checkbox').click(function(){
  // кэшируем узлы
  var items = $('#goods').find('.item');
  var checked = $(':checked');

  // убрать подсветку со всех товаров
  items.removeClass('highlighted');

  // Если отмечен хотя бы один чекбокс – фильтровать
  if (checked.length>0) {
    items
      .css({'opacity':'.3'})
      .filter(getFilteredItems('foo'))
      .filter(getFilteredItems('bar'))
      .addClass('highlighted');
  }
  else { // иначе – ничего не делать
    items.css({'opacity':'1'});
  }
});


Всё прекрасно работает, если есть хотя бы один чекбокс в двух категориях одновременно. Но если только в одной, то на выходе из фильтра – 0 элементов.
Как сделать так, чтобы при отмеченных чекбоксах только одной категории фильтра отсутствие отмеченных во второй не фильтровало все элементы до нуля?

Я пробовал топорно возвращать результаты фильтра в переменные и сделать условия:
var fooItems = items.filter(getFilteredItems('foo'));
var barItems = items.filter(getFilteredItems('bar'));
if (fooItems.length > 0 && barItems.length > 0) {
  // фильтр по двум категориям
} else if (fooItems.length > 0) {
  // фильтр только по foo
} else if (barItems.length > 0) {
  // фильтр только по bar
}

Но на мой взгляд так писать грубо, неправильно и поддерживать это ужасно неудобно (особенно, в случае добавления бОльшего количества категорий).
Как мне изменить код?

Спасибо!

ps: В некоторых случаях (но далеко не всегда) отмечание чекбокса подвешивается где-то на >400 мс. Меня это очень сильно печалит. Если кто-то даст советы по оптимизации данного кода – буду рад критике!

Последний раз редактировалось TrogWar, 05.05.2013 в 17:38. Причина: Очепятки + добавлены комменты в код + добавлен ps
Ответить с цитированием
  #2 (permalink)  
Старый 05.05.2013, 18:12
Аватар для ksa
ksa ksa вне форума
CacheVar
Отправить личное сообщение для ksa Посмотреть профиль Найти все сообщения от ksa
 
Регистрация: 19.08.2010
Сообщений: 14,123

Сообщение от TrogWar
В некоторых случаях (но далеко не всегда) отмечание чекбокса подвешивается где-то на >400 мс. Меня это очень сильно печалит. Если кто-то даст советы по оптимизации данного кода – буду рад критике!
Попробуй такой вариант...

<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<!--
<link rel="stylesheet" type="text/css" href="tmp.css" />
-->
<style type="text/css">
.on {
	border: 1px solid;
}
</style>
<script type="text/javascript">
$(document).ready(function (){
	$('#case > input:checkbox').click(function (){
		$('#items > .item').removeClass('on');
		var fltr=filter();
		if (fltr=='') return;
		$('#items > .item'+fltr).addClass('on');
	});
});
function filter() {
	var str='';
	$('#case > input:checkbox:checked').each(function (){
		var typ=$(this).data('type');
		str=str+'[data-'+typ+'="'+$(this).data(typ)+'"]'
	});
	return str;
};
</script>
</head>
<body>
<!-- Чекбоксы -->
<div id='case'>
	<input type="checkbox" data-type="foo" data-foo="foo_item1" />
	<input type="checkbox" data-type="foo" data-foo="foo_item2" />
	...
	<input type="checkbox" data-type="bar" data-bar="bar_item1" />
	<input type="checkbox" data-type="bar" data-bar="bar_item2" />
</div>
<!-- Товары -->
<div id='items'>
	<div class="item" data-foo="foo_item1" data-bar="bar_item1">
		foo_item1 bar_item1
	</div>
	<div class="item" data-foo="foo_item2" data-bar="bar_item2">
		foo_item2 bar_item2
	</div>
	...
</div>
</body>
</html>
Ответить с цитированием
  #3 (permalink)  
Старый 05.05.2013, 18:21
Интересующийся
Отправить личное сообщение для TrogWar Посмотреть профиль Найти все сообщения от TrogWar
 
Регистрация: 15.04.2012
Сообщений: 12

ksa, спасибо! Согласен – я совсем забыл, что
$(':checked')
дольше, чем даже
$('#filter').find(':checkbox');
или ещё лучше
$('#filter').find('input').filter(':checkbox');
чтобы использовался
querySelectorAll();
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
не подключается filter в ie 6-7 shtopor Internet Explorer 4 23.03.2013 20:58
Смена нескольких картинок при наведении Demoni Элементы интерфейса 8 28.04.2012 23:57
Автоматическая смена нескольких картинок utb jQuery 4 24.01.2012 12:47
какое отличие между filter и is Arkinsstoun jQuery 5 19.01.2012 22:18
поменять цвет у нескольких строк в таблице Root Элементы интерфейса 4 21.04.2008 10:30