2

I have a CMS generating a basic navigation using a UL. Each first-level LI is styled to be a group. I need to apply a style to the last element within each of the first level LI "groups". Meaning; if a first-level LI has no children, I want to apply a style to it (as the "bottom" of the group); if it does have children, I want to find the last child OR grandchild element that appears (again, the "bottom" of the group). I have used both CSS and Javascript "last" classes, and have successfully applied styles to the last child of a certain depth within the first-level LI, but that isn't helpful since the bottom button of the list is of an unknown depth.

My line of thinking involves a IF statement that finds the last child of the first level, checks if it has children, and if it does, go another level deep and find that last child and checks for children, repeating this process until it finds the last LI that does not have children within the first-level LI groups. However, I am a JS noob and am not sure how to go about that.

I am open to CSS or JavaScript/jQuery solutions. I have been banging my head on this one for a while and appreciate any input or better ideas. Thanks for your help!!

--

Update: here's a code sample of what I am hoping for:

<ul id="navigation>
  <li>Item one</li>  <!--Style this one-->
  <li>Item Two
    <ul>
      <li>Item Two-One</li>
      <li>Item Two-Two</li>  <!--Style this one-->
    </ul>
  <li>
  <li>Item Three
    <ul>
      <li>Item Three-One</li>
      <li>Item Three-Two
        <ul>
          <li>Item Three-Two-One</li>
          <li>Item Three-Two-One</li>  <!--Style this one-->
        </ul>
      </li>
    </ul>
  <li>
  <li>Item Four
    <ul>
      <li>Item Four-One</li>
      <li>Item Four-Two
        <ul>
          <li>Item Four-Two-One</li>
          <li>Item Four-Two-One</li>
        </ul>
      </li>
      <li>Item Four-Three</li>  <!--Style this one-->
    </ul>
  <li>
</ul>

The reason the .last selector doesn't work is because, in the above example, it would style item Four-Two-One since it is the last element of its UL.

Ryan
  • 45
  • 7
  • 1
    can you show us a visual example of what you are after? or your :first, :last example to see where you are at. – rlemon Nov 01 '11 at 15:14
  • possible duplicate of [select deepest child in jQuery](http://stackoverflow.com/questions/3787924/select-deepest-child-in-jquery) – pimvdb Nov 01 '11 at 15:16
  • 1
    @Ryan: It sounds like you're looking for the "deepest" last child `li` in a nested list, but I'm not certain. Could you perhaps post a code sample, showing which element(s) you're looking to select? – Jordan Gray Nov 01 '11 at 15:22
  • @Jordan, I am not quite looking for the "deepest" last child, as the last may not be the deepest. Sorry for the absence of a code example - I have added one above. Thanks much! – Ryan Nov 01 '11 at 15:48
  • Honestly, if your jQuery is this complicated and convoluted to write, you're doing it wrong. You need to reapproach how you're styling this list in a more logical fashion. You can't code what you don't understand. – Cory Danielson Nov 01 '11 at 16:36
  • @ImportedNoob; Like I said, I'm open to suggestions for a better route, and my reason for asking here is to see if there is a non-convoluted way to accomplish this. You'll never understand what you don't try to code. – Ryan Nov 01 '11 at 16:43
  • Could you mock up what you're at least trying to accomplish so that we can have a better idea as to what the result should look like? – Cory Danielson Nov 01 '11 at 16:58
  • @ImportedNoob; My development site can be viewed at test.childrenscancer.org, but what I am working on will only appear when viewing on (or simulating) a mobile device. From a mobile, hitting the "Menu" button on the top-right will slide in a menu. I'd love to be able to put a rounded corner on the 's in the last item on each section. I'm close to forgetting the whole thing, but I appreciate any advice you have to offer. Thanks! – Ryan Nov 01 '11 at 17:10
  • @Ryan, as a last-thing-then-i'm-done-with-this-question, is this the only reason for doing this? to round the last item. Are you sure you do not want to just add a classname to that last item in your markup? it would speed things up considerably. especially if you are running this on a mobile device, you want to use as little jquery as possible. `jQuery === bloated mess` – rlemon Nov 01 '11 at 19:28

3 Answers3

2

I think this is what you want. It's part of the jQuery API.

http://api.jquery.com/last/

HTML

<ul>
  <li>list item 1</li>
  <li>list item 2</li>
  <li>list item 3</li>
  <li>list item 4</li>
  <li>list item 5</li>
</ul>

jQuery

$('li').last().css('background-color', 'red');

EDIT:

Okay I figured out a way for you to do it.. the only caveat is that you need to be able to set a class for the first level of <li>'s. I've posted my findings here:

http://jsfiddle.net/TTXch/54/

It selects the last of the <li>'s for each main navigation element. Your posted structure was a little off... the end tags didn't all match up. Anyway, check out the jQuery in the javascript window in the jsFiddle.

tedski
  • 2,271
  • 3
  • 27
  • 48
  • The trouble with this solution is that it would not select the children of "list item 5" specifically, much less find the last child or grandchild (whichever is at the bottom). Am I making any sense? Thanks! – Ryan Nov 01 '11 at 15:52
  • Will you have a static number of levels? or is it dynamic? – tedski Nov 01 '11 at 17:59
  • It will never be more than four levels deep, but it is dynamic and based on a shifting sitemap, so I would rather not hard-code which items get the treatment. – Ryan Nov 01 '11 at 18:28
  • Thanks! Very elegant solution. However, I am going with @rlemon's solution since it does not require the classname on the first-level LI's. Thanks for your work! – Ryan Nov 01 '11 at 19:07
2

To clean up my answer, incase this is read at a later date.

here is my solution to your problem:

var checkChildren = function($this) {
    if (!$this.children().length) {
        $this.css({
            color: '#f00',
            fontWeight: '700',
            textDecoration: 'underline'
        });
        return false;
    }
    return true;
};
$("#navigation").children("li").each(function() {
    $these = $(this);
    while (checkChildren($these)) {
        $these = $these.children().last() || $these.next();
    }
});
rlemon
  • 17,518
  • 14
  • 92
  • 123
  • 1
    `.children("li:last")` could also be replaced with `.children("li").last()` – rlemon Nov 01 '11 at 15:32
  • Thank you, this is close, but it selects any item that happens to be last of a set, so in the code sample I just threw on to my post, it applies to item Four-Two-One. – Ryan Nov 01 '11 at 16:05
  • what is the logic behind not selecting four-two-one but selecting three-two-one?? – rlemon Nov 01 '11 at 16:51
  • Three-two-one is the last item of the top-level LI's. Four-two-one is not the last item of its section, four-three is. Visually, the top level LI's (Item One, Two, Three) are groups, and I just want to apply an effect to whatever element is at the bottom of each of these groups. Does that make sense? Am I confusing the masters here? :) – Ryan Nov 01 '11 at 16:57
  • no I just had my nested lists written in a very dumb way. Give me a minute lemmy see what I can do. – rlemon Nov 01 '11 at 17:05
  • That is absolutely perfect. Thank you very much for your help!! – Ryan Nov 01 '11 at 19:04
0

You should be able to use the jQuery last selector for this (http://api.jquery.com/last-selector/).

ckpepper02
  • 3,297
  • 5
  • 29
  • 43