jQuery: Agrupación de Elementos Similares

El uso de jQuery, estoy tratando de grupo de elementos similares en una lista. Esto es lo que yo estoy tratando de hacer. Dada una lista como la siguiente:

<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>

Me gustaría terminar con los siguientes:

<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>

En definitiva, en cualquier momento hay 2 o más elementos con class="foo", que debe ser agrupados juntos hasta llegar a una no-clase="foo" elemento. Puedo utilizar un enlace para mostrar u ocultar los elementos agrupados.

  • Respuesta seleccionada
    user113716
    3 de octubre de 2010

    He aquí una posibilidad:

    Ejemplo: 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: Corregido un error con el len variable, y se añadió un ejemplo.


    Explicación: Lo que está sucediendo con el .filter() es que se está reduciendo la li.foo los elementos de abajo a la primera en un grupo (tiene al menos un li.foo después de ella, y no antes).

    A continuación, con el .each() agrega la <a>, obtener el siguiente elementos hasta que llega a uno que no es li.foo, envuelve a aquellos con un <ul> y devuelve cómo muchos de los que allí estaban usando length la propiedad.

    Luego nos atraviesan a que los nuevos <ul> y anexar a la primera li.foo en el grupo.

    Finalmente se le añade la cantidad que se almacena en el length propiedad a la <a> elemento.

1 Respuestas

  • jcubic
    3 de octubre de 2010

    Me encuentro con esto:

    $(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);
            });
        }
    });