views:

36

answers:

2

Hi,

I am trying to start writing some simple jQuery plugins and for my first try if figured I would write something that does nothing else but apply .first & .last classes to passed elements.

so for instance i want to ultimately be able to:

$('li').firstnlast();

So that in this html structure:

<ul>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
</ul>
<ul>
    <li></li>
    <li></li>
</ul>

it would create the following:

<ul>
    <li class="first"></li>
    <li></li>
    <li></li>
    <li class="last"></li>
</ul>
<ul>
    <li class="first"></li>
    <li class="last"></li>
</ul>

What i have written so far in my plugin is this:

(function($) {

    $.fn.extend({
        firstnlast: function() {
            $(this)
                .first()
                .addClass('first')
                .end()
                .last()
                .addClass('last');
        }
    });
})(jQuery);

However the above only returns this:

<ul>
    <li class="first"></li>
    <li></li>
    <li></li>
    <li></li>
</ul>
<ul>
    <li></li>
    <li class="last"></li>
</ul>

It seems that passing only the li into the function it will look at all li elements on the entire page and then apply the classes to it.

What I need to figure out is how i can basically make the function 'context aware' so that passing the above li into the function would apply the classes to those lis inside of the parent ul, not to the first and last li on the entire page.

Any hints, ideas and help would be much appreciated.

Thanks for reading,

Jannis

+3  A: 

You want to use :first-child and :last-child to get those <li>s there here, like this:

this.filter(':first-child:not(:last-child)').addClass('first')
    .end().filter(':last-child:not(:first-child)').addClass('last');

This gets the first and last with respect to the parent, which seems to be what you're after, give it a go :)

Updated: Now handles the case of 1 <li> inside a <ul>, these elements will be ignored.

Nick Craver
Thank you, this works great. However this also applies both classes if there is a `ul` with only 1 `li` element inside. Is there any way I can have this function only apply if there are more than 1 of the given element?
Jannis
@Jannis - Try the updated answer, it should ignore these single `<li>` cases.
Nick Craver
Thanks again! This works perfectly and I just learned another cool thing about jQuery. Awesome!
Jannis
A: 
(function($) {

    $.fn.extend({
        firstnlast: function() {
            $(this).parent()
                .find("li:eq(0)")
                .addClass('first')
                .end()
                .find("li:eq(-1)")
                .addClass('last');
        }
    });
})(jQuery);
David Murdoch
This restricts his extension to working on `<li>` , and if the last `<li>` contained a list with li's...more errors :)
Nick Craver
@Nick Craver...oops, very obvious. Thanks for pointing that out.
David Murdoch