简体   繁体   中英

jQuery: Grouping Similar Items

Using jQuery, I'm trying to group similar items in a list. Here's what I'm trying to do. Given a list like the following:

<ul>
    <li class="foo">Item #1</li>
    <li class="foo">Item #2</li>
    <li class="foo">Item #3</li>
    <li class="bar">Item #4</li>
    <li class="bar">Item #5</li>
    <li class="foo">Item #6</li>
    <li class="foo">Item #7</li>
    <li class="bar">Item #8</li>
</ul>

I'd like to end up with the following:

<ul>
    <li class="foo">Item #1 <a>2 More Like This</a>
        <ul>
            <li class="foo">Item #2</li>
            <li class="foo">Item #3</li>
        </ul>
    </li>
    <li class="bar">Item #4</li>
    <li class="bar">Item #5</li>
    <li class="foo">Item #6 <a>1 More Like This</a>
        <ul>
            <li class="foo">Item #7</li>
        </ul>
    </li>
    <li class="bar">Item #8</li>
</ul>

In short, anytime there's 2 or more items with class="foo", they should be grouped together up until reaching a non-class="foo" item. I can then use a link to show or hide the grouped items.

Here's one possibility:

Example: http://jsbin.com/ipiki3/3/

$('ul > li.foo')
    .filter(function() {
        var $th = $(this);
        return $th.next('li.foo').length && !$th.prev('li.foo').length;
    })
    .each(function() {
        var $th = $(this);
        var len= $th.append('<a href="#"> more like this</a>')
                    .nextUntil(':not(li.foo)').wrapAll('<ul>').length;
        $th.next('ul').appendTo(this);
        $th.children('a').prepend(len);
    });

EDIT: Fixed a mistake with the len variable, and added an example.


Explanation: What's happening with the .filter() is that it is narrowing the li.foo elements down to the first in a group (has at least one li.foo after it, and none before) .

Then with the .each() it appends the <a> , get's the next elements until it reaches one that is not li.foo , wraps those with a <ul> and returns how many there were using the length property.

Then we traverse over to that new <ul> and append it to the first li.foo in the group.

Finally we prepend the quantity we stored in the length property to the <a> element.

I come up with this:

$(document).ready(function() {
    var groups = {}
    $('ul li').each(function() {
        var self = $(this);
        var class_name = self.attr('class');
        if (class_name) {
            if (typeof groups[class_name] == 'undefined') {
                groups[class_name] = [];
            }
            groups[class_name].push(self);
        }
    });
    var ul = $('ul');
    ul.empty();
    for (var class_name in groups) {
        var array = groups[class_name];
        ul.append('<li class="' + class_name + '">' + $(array[0]).html() + 
            '<a>More Like this</a><ul></ul>');
        $(array.splice(1)).each(function() {
            ul.find('li.' + class_name + ' ul').append(this);
        });
    }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM