JQuery: использовать фильтр(), но работать с обоими результатами

В jQuery filter() сводит ваш результат к тем элементам, которые выполняют определенное условие.

Это разбиение списка на две части. Работа с "хорошей половиной" элементов проста:

$("some selector").filter(function() {
  // determine result...
  return result;
}).each( /* do something */ );

Но как я могу работать с "другой половиной" моих элементов, но не делая этого эквивалента:

$("some selector").filter(function() {
  // determine result...
  return !result;
}).each( /* do something else */ );

В принципе, я хотел бы передать две отдельные части /* do something */ в один фильтр. Один для тех, которые соответствуют, и один для остальных - без необходимости фильтровать дважды. У меня отсутствует функция jQuery, которая делает это?


P.S.: Думаю, я мог бы сделать:

$("some selector").each(function() {
  // determine result...
  if (result)
    /* do something */
  else
    /* do something else */
});

Но я надеялся на что-то приятнее.

Ответы

Ответ 1

Метод, рекомендованный Kobi в форме плагина:

$.fn.invert = function() {
  return this.end().not(this);
};

$('.foo').filter(':visible').hide().invert().show();

Обратите внимание, что invert() не добавит новый элемент в стек jQuery, а заменит последний:

$('.foo').filter(':visible').invert().end(); // this will yield $('.foo'), not $('.foo:visible')

Изменить: изменено prevObject на end() по предложению Tomalak.

Ответ 2

Я обычно использую not для этого - он может принимать множество элементов и удалять их из вашего выбора, оставляя вас с дополнением

var all = $("some selector");
var filtered = all.filter(function() {
  // determine result...
  return result;
});
var others = all.not(filtered);

Ответ 3

Вы можете попробовать свои силы при написании плагина jQuery для этого. Проверьте код функции фильтра и придумайте что-то, что более точно, что вы хотите. Это может быть что-то вроде:

$("some selector").processList(predicate, successCallback, failureCallback);

Затем вы передадите три обратных вызова: один, который оценивает объект, чтобы увидеть, соответствует ли он выбранному фильтру (вы также можете принять селекторную строку или тому подобное); тот, который обрабатывает объекты, соответствующие выбранному, и другой, который обрабатывает объекты, которые не совпадают.

Ответ 4

Я не знаю, хорошо ли это, но с помощью filter() вы можете сделать что-то вроде:

var $others = $();

var $filtered = $('div').filter(function() {
    if(! your filter test) {
        $others.push(this);
    } else {
        return true; 
    }
});

alert($others.length);
alert($filtered.length);

EDIT:

Сначала я попробовал его, начиная с пустого набора jQuery $(), а затем используя add(), чтобы заполнить его результатами без фильтра, но не смог заставить его работать.

EDIT:

Обновлено для использования push непосредственно на пустом объекте jQuery, как предлагается Tomalak.

Ответ 5

$.fn.if = function(cond, ontrue, onfalse) {
  this.each(function() {
    if (cond.apply(this)) ontrue.apply(this);
    else onfalse.apply(this);
  });
};

$('some selector').if(function() {
  // determine result
}, function() {
  // do something
}, function() {
  // do something else
});

Я не уверен, что это гораздо более читаемо, чем если бы каждый из них был включен вручную.

Ответ 6

Интересный вопрос. Я вижу, вы склоняетесь к тому, что я собираюсь предложить:

$("some selector").each(function() { 
  if ($(this).is(SOMEFILTER)) { 
    // do something
  } else {
    // do something  
  }
  // continue with things that apply to everything
});