tags:

views:

1937

answers:

7

I have the following:

<ul id="list">
<li>item1
    <ul>
     <li>sub1</li>
     <li>sub2</li>
    </ul>    
</li>
</ul>

I'd like to respond to a li click event and use the text of the li elsewhere. However, if the click is on an li that contains a nested ul, I of course get the text of all elements.

$("#list li").click(function() {
    alert($(this).text());
});

returns item1sub1sub2, as expected.

I can't figure out how to get just 'item1' if the item 1 li is clicked. I tried the following (among other things) with no luck:

$("#list li").click(function() {
    alert($(this).filter("ul").text());
});

Any ideas?

EDIT

This is a snippet of an example - it could be multiple levels deep. I also do not want to wrap the list item text in a span or other markup.

+3  A: 

you're having a hard time because text() does what it should - returns the text of this and all child elements. The easiest thing to do is to add another tag to every <li>, and use this tag.
For example:

<ul id="list">
<li><span>item1</span>
    <ul>
        <li><span>sub1</span></li>
        <li><span>sub2</span></li>
    </</ul>    
</li>
</ul>

And then you have a simple selector:

$("#list li").click(function() {
   alert($(this).find("span").eq(0).text());
});

or, if possilbe (depending on your style), you may add the event to the span:

$("#list span").click(function() {
   alert($(this).text());
});

If you cannot add these <span>s (as you say) you can use jQuery's .contents() to add them for you, similar to what was done here:

http://stackoverflow.com/questions/992472/hide-b-in-xabr-b-x/992568#992568

Kobi
A: 

So this mechanism pulls out the html from the child element, replaces the newlines with nothing, and then returns the string only up to the first "<" character. I also added event.stopPropagation to avoid calling the click event bubbling up to the parent.

<script type="text/javascript">
$("#list li").click(function(event) {
    var sourceHTML = $(this).html().replace(/\n/g,'').replace(/<.*/,'');
    alert(sourceHTML);
    event.stopPropagation();
});
</script>
artlung
A: 

Hi there,

I think you need to use the each method. so try the following script:

$(document).ready(function() {
        $('ul').each(function() {
            $(this).find('li').click(function() {
                var listItem = this;
                alert($(listItem).text());
            });
        })
    });

with the following markup

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>
Ali
Hello. text() on an li element will still return the full text of all children. In fact, the each() is redundant here, it's the same as `$(ul li).click`
Kobi
+1  A: 

This checks if the list item has any children and if so it filters out only the text nodes and concatenates the result (in this case it will work for text elements wherever they're put in the li). If you only ever want to check for elements at the start you can avoid the for loop and just work with this.firstChild

$("#list li").click(function(e) {
    if ($(this).children().length > 0) {
       var text = "";
       for (var i = 0; i < this.childNodes.length; i++) {
           var node = this.childNodes[i];
           if (node.nodeType === 3 && $.trim(node.nodeValue).length > 0) {
                text += $.trim(node.nodeValue);
           }
       }
       alert(text);
    }
    else {
       alert($(this).text());
    }
    e.stopPropagation();
});
sighohwell
+4  A: 

What about this approach? Clone the object, remove the clone's children and then find the text content.

$("#list li").click(function () {
    alert($(this).clone().children().remove().end().text());
}

Perhaps not the most efficient approach, but it's entirely intuitive, pretty tidy, and you don't have to muck with your html.

ozan
Thanks, this works well. I've selected this as the correct answer, but I may add a span around the text to make this a little bit cleaner in this case. Still a good tip for similar situations.
ScottE
A: 

Hi, I did it like that:

$( $("#list li.sel").not("ul").contents().get(0) ).text()

<ul id="list">
<li>item1
    <ul>
        <li>sub1</li>
        <li class="sel">sub2
         <ul>
          <li>sub2.1</li>
          <li>sub2.2</li>
         </ul>
        </li>
    </ul>    
</li>
</ul>
Christoph
+1  A: 

Normal DOM methods allow to access text contents for just one element, rather than jquery:

$("#list li").click(function() { alert($(this)[0].firstChild.textContent) });

firstChild in this case is the textNode beneath the li element

Josh