MrLewk
MrLewk

Reputation: 498

use jQuery to expand/collapse ul list - having problems

I'm trying to create a blog archive list which shows all articles by year and month (which I've done with PHP/MySQL)

Now I'm trying to make it so that on page load, all years are collapsed except the latest year/month and also that each will collapse/expand on click.

At the moment my jQuery click function will open or close all of the li elements rather than just the one I click. I'm still pretty new to jQuery so am not sure how to make it just affect the list section that I click on.

Any help would be grand!

Here's my code so far (the list is generated from PHP/MySQL loops)

<ul class="archive_year">
<li id="years">2012</li>
    <ul class="archive_month">
        <li id="months">September</li>
            <ul class="archive_posts">
                <li id="posts">Product Review</li>
                <li id="posts">UK men forgotten how to act like Gentlemen</li>
                <li id="posts">What Do Mormons Believe? Ex-Mormon Speaks Out</li>
                <li id="posts">Here is a new post with lots of text and a long title</li>
            </ul>
        <li id="months">August</li>
            <ul class="archive_posts">
                <li id="posts">A blog post with an image!</li>
            </ul>
    </ul>
<li id="years">2011</li>
    <ul class="archive_month">
        <li id="months">July</li>
            <ul class="archive_posts">
                <li id="posts">New Blog!</li>
            </ul>
    </ul>
<li id="years">2009</li>
    <ul class="archive_month">
        <li id="months">January</li>
            <ul class="archive_posts">
                <li id="posts">Photography 101</li>
            </ul>
    </ul>
</ul>​

And here is the jQuery so far:

$(document).ready(function() {

//$(".archive_month ul:gt(0)").hide();

$('.archive_month ul').hide();

$('.archive_year > li').click(function() {
    $(this).parent().find('ul').slideToggle();
});

$('.archive_month > li').click(function() {
    $(this).parent().find('ul').slideToggle();
});


});

I was experimenting with the $(".archive_month ul:gt(0)").hide(); but it didn't work as expected, it would switch the open and closed around.

Any help/thoughts?

Also, here is a fiddle for live example: http://jsfiddle.net/MrLuke/VNkM2/1/

Upvotes: 12

Views: 46288

Answers (2)

Meloman
Meloman

Reputation: 3712

I use this to show history on invoices in my ERP, it works like a charm :

  • list shows only the last event (last li)
  • "display more" element with count of hidden events
  • onclick, shows all hidden events and hide my "display more" element

In example below, the second line "show more" element has been clicked :

ERP invoices history ul>li list with hidden elements

HTML / Smarty Template :

<td class="col-xs-2" id="iv-status-{$invoice.sale_invoice_id}">
    <ul class="history" id="history-{$invoice.sale_invoice_id}">
        {if $invoice.events|@count > 1}
            <li class="history-more">
                <i class="fal fa-ellipsis-h"></i> 
                afficher {$invoice.events|@count} évènements
            </li>
        {/if}
        <li class="history-hidden">
            <b>{$invoice.dates.created.timeline}</b><br>
            <i class="fal fa-file-plus"></i> Facture créée par {$invoice.log.employee.firstname}
        </li>
        {foreach $invoice.events as $ev}
            {if $ev.event == 'download'}
                <li class="history-hidden">
                    <b>{$ev.dates.timeline}</b><br>
                    <i class="fal fa-download"></i> Facture téléchargée par {$ev.employee.firstname}
                </li>
            {/if}
            {if $ev.event == 'print'}
                <li class="history-hidden">
                    <b>{$ev.dates.timeline}</b><br>
                    <i class="fal fa-print"></i> Facture imprimée par {$ev.employee.firstname}
                </li>
            {/if}
            ...
            {if $ev.event == 'close'}
                <li class="history-hidden">
                    <b>{$ev.dates.dateline}</b><br>
                    <i class="fal fa-file-check"></i> Facture clôturée par {$ev.employee.firstname}
                </li>
            {/if}
        {/foreach}
    </ul>
</td>

jQuery :

$('.history').each(function() {
    $('.history li:last-child')
        .addClass('history-last')
        .removeClass('history-hidden');
    $(this).children('li.history-more').click(function(e) {
        ul = $(this).parent('ul').attr('id');
        $('#' + ul).children('li.history-more').hide();
        $('#' + ul).children('li.history-hidden').show();
    });
});

CSS :

li.history-more {
    cursor: pointer;
}
li.history-hidden {
    display: none;
}

Upvotes: 0

Zoltan Toth
Zoltan Toth

Reputation: 47667

First about the issues:

  1. ID-s must be unique!
  2. You have to properly nest your <li>-s

And here is how you can solve the problem - DEMO

jQuery

$('.archive_month ul').hide();

$('.months').click(function() {
    $(this).find('ul').slideToggle();
});

HTML (fixed)

<ul class="archive_year">
<li class="years">2012
    <ul class="archive_month">
        <li class="months">September
            <ul class="archive_posts">
                <li class="posts">Article 1</li>
                <li class="posts">Article 2</li>
                <li class="posts">Article 3</li>
                <li class="posts">Article 4</li>
            </ul>
        </li>
        <li class="months">August
            <ul class="archive_posts">
                <li class="posts">Article 1</li>
            </ul>
        </li>
    </ul>
</li>
<li class="years">2011</li>
    <ul class="archive_month">
        <li class="months">July
            <ul class="archive_posts">
                <li class="posts">Article 1</li>
            </ul>
        </li>
    </ul>
</li>
<li class="years">2009</li>
    <ul class="archive_month">
        <li class="months">January
            <ul class="archive_posts">
                <li class="posts">Article 1</li>
            </ul>
        </li>
    </ul>
</ul>

Upvotes: 26

Related Questions