views:

89

answers:

4

I am using the following jQuery

var etag = 'kate'
if (etag.length > 0) {
    $('div').each(function () {
        $(this).find('ul:not(:contains(' + etag + '))').hide();
        $(this).find('ul:contains(' + etag + ')').show();
    });
}​

towards the following HTML

<div id="2">
<ul>
  <li>john</li>
  <li>jack</li>
</ul>
<ul>
  <li>kate</li>
  <li>clair</li>
</ul>
<ul>
  <li>hugo</li>
  <li>desmond</li>
</ul>  
<ul>
  <li>said</li>
  <li>jacob</li>
</ul>
  </div>

    <div id="3">
<ul>
  <li>jacob</li>
  <li>me</li>
</ul>
<ul>
  <li>desmond</li>
  <li>george</li>
</ul>
<ul>
  <li>allen</li>
  <li>kate</li>
</ul>  
<ul>
  <li>salkldf</li>
  <li>3kl44</li>
</ul>
</div>

basically, as long as etag has one word, the code works perfectly and hides those elements who do not contain etag. My problem is, when etag is multiple words (and I don't have control over it. Its coming from a database and could be combination of multiple words separated with space char) then the code does not work..

is there any way to achieve this?

A: 

A slightly different approach - try this:

    var etag='kate test blah';

    var tags = etag.split(' ');
    $('div ul').each(function () {
      var list = $(this);
      list.hide();
      list.children('li').each(function() {
        var item = $(this);
        if ($.inArray(item.html(), tags) >= 0) list.show();
      });
    });

Written in the browser, so sorry if there are any bugs!

-- edit --

Actually, I reread the question, and that code won't work. You need to define the behaviour more first - does the list have to contain all of the tags, or just one of the tags to be shown?

-- edit 2 --

Code updated. Kind of inefficient, but it should do the job.

zaius
thank you for trying to help. the list can contain any of the words in etag.
Emin
also this didn't work
Emin
Another question: do you want to hide the whole div if it contains any of those names? or just the UL containing that name?
zaius
I only need to hide the ULs
Emin
I had > 0 and it should have been >= 0. Try it again and tell me if it works.
zaius
A: 

Another approach:

var etag='Some text from server';

if (etag.length > 0) {
    $('div ul').each(function () {
        var el = $(this); // Local reference
        (el.html() === etag) ? el.show() : el.hide(); 
    });
}​
shazmo
shazax unfortunately this did not work
Emin
+1  A: 

This filter checks if any of the words in the given string match the text of the element.

jQuery.expr[':'].containsAny = function(element, index, match) {
    var words = match[3].split(/\s+/);
    var text = $(element).text();
    var results = $.map(words, function(word) {
        return text === word;
    });
    return $.inArray(true, results) !== -1;
};

Show and hide as:

$('ul').hide();
$('li:containsAny(john kate)').parents('ul').show();

See an example here.

Anurag
I don't think this works for a lot of cases, for example: http://jsfiddle.net/ZXdAH/
Nick Craver
thanks for pointing that out @Nick. Update code to use exact matches instead, otherwise words like "kat" and "joh" would slip through.
Anurag
@Anurag thank you. this did the trick for me however, I want to clarify something. I am using this to filter a list of items based on tags. I populate a list of checkboxes of tags. the user selects 1 or many tags and clicks on filter button. Upon click, the code loops through the checked checkboxes and adds them into a string. then I run your code to hide those which do not have the tags and only show the ones which does. The list can be up to 1000 items long. Is this solutions feasible? is there any better way? Any performance issues? any live sites doing what I need? thanks in advance!
Emin
Do the ul's only contain tags in them? 1000 items is not a lot but you may still see a performance dip in IE. Although it's a small number and totally feasible, you should write a couple of speed tests and run on various browsers before considering alternative approaches.
Anurag
+2  A: 

You could turn this into a function that takes any number of words separated by a character, like this:

function filter(words) {
    var uls = $('div ul').hide();
    $.each(words.split(' '), function(i, v) {
        uls = uls.filter(':contains(' + v + ')');
    });
    uls.show();
}

//sample call
var etag='kate clair'
filter(etag);

You can see a working demo here

This finds <ul> elements that contain all the words in the given string.

Nick Craver
While this also works, I guess I couldn't ask my question properly. Basically your code only returns the <ul> that has <li>kate and <li>clair. But it should also return <li>allen and <li>kate. However, this also, is something I will require in another part of my project. So thank you! one vote up :)
Emin
@Emin - Make sure in your future questions to state whether it's a "contains any" or "contains all" (big difference!) that you're after :) Glad you got it working!
Nick Craver