views:

1136

answers:

9

I want to create an array of all the html elements within a div that contain text strings, such as

<p>some string</p>.

I don't want to get hold of the strings, I want the array items to be the elements (in the example, would be the p node). I do not know before hand what the strings will be, so I can't look for string values to match. I also don't want empty text nodes to end up in the array.

Thanks!

+1  A: 

You could cycle through the children and grab everything that has a .text() value != ""

Jonathan Sampson
That sounds like a good plan but I don't know jQuery well enough to understand how construct syntax that does what you describe. Can you produce an example?Thanks.
Tim Sheiner
A: 

d is the div under which you want to find things
v is an empty array
i you have to start out at 0.

The $.trim is used so that you don't get nodes that are just whitespace.

$("*",d).filter( function() { 
     return $.trim($(this).text()) != ""
  } ).each( function() { 
     v[i] = $(this).text(); 
     i++; 
  } );

One can also use v.push($(this))...which is something that totally slipped my mind.

Thomas
This looks promising, will try it. If I only want the elements, not the actual text would the final assignment be: v[i] = $(this);?
Tim Sheiner
It depends on whether you want it to be a jQuery object or not. If you want it to be a jQuery object, it would be $(this). If you just want the DOM element, it would just be this.
Thomas
And actually, you wouldn't even need to do that...all you would have to do is remove the .each(), since the only purpose for that was to pull out the text. (Sorry, I was somewhat distracted when I made the last comment.
Thomas
+1  A: 
var array = [];
var divSelector = "div.mine";

$(divSelector).contents().each(function()
{
   // If not an element, go to next node.
   if (this.nodeType != 1) return true;       

   var element = $(this);
   if ($.trim(element.text()) != "")
     array.push(element);
});

array is the array of elements that have some text in them.

cdmckay
A: 
 $(function() {
        var array = new Array();
        $("#testDiv *").each(function(x, el) {

            if ($.trim($(el).text()) != '' ) {
                array.push(el);
            }
        });
        alert(array.length);
    });
bashmohandes
+2  A: 

You can make use of not and the empty selectors to get the non-empty elements while converting to an array can be achieved using get

$("#theDiv > :not(:empty)").get();

The above selector gets all the children elements of "theDiv" and that aren't empty (i.e. they either have children or text) and then converts the matched set to an array.

If you want only elements that have text inside them, this should work...

$("#theDiv > :not(:empty, :has(*))").get();

To get rid of elements that have whitespace you can make use of filter

$("#theDiv > :not(:has(*))").filter(function() { 
                 return $.trim(this.innerHTML).length > 0;
         }).get();
sighohwell
This won't work if he wants elements that ONLY have text inside. This also returns any elements that have any children, even if none of those children have text inside of them.
TM
Another note, this would only work on immediate children of the div as well (not sure if this is the desired behavior or not). Remove the > to check all ancestors. The * also serves no purpose in this case.
TM
Updated regarding selecting elements that only have text inside. Thanks for picking up on the * I've updated my answer accordingly
sighohwell
Lower selector is almost right, but it will select elements that have empty (all whitespace) text nodes as well.
TM
Got me on that one :). I was just trying to find a way to do it with a one-liner without resorting to anything like a closure (a subsequent call to filter would get rid of the elements with whitespace) or custom selector.
sighohwell
Looks like this latest one should work :)
TM
+4  A: 

A custom selector could be helpful in your case:

jQuery.expr[':'].hasText = function(element, index) {
     // if there is only one child, and it is a text node
     if (element.childNodes.length == 1 && element.firstChild.nodeType == 3) {
        return jQuery.trim(element.innerHTML).length > 0;
     }
     return false;
};

After that, you can simply do this:

$('#someDiv :hasText') // will contain all elements with text nodes (jQuery object)
$('#someDiv :hasText').get() // will return a regular array of plain DOM objects

I am assuming that you are only trying to select elements that have ONLY text inside of them.

TM
Great answer, just a minor typo -- nodeType should be checked instead of nodeValue...
sighohwell
Good call, my mistake
TM
A: 

Use the :contains selector:

var matches = new Array();
$('#start_point *:contains(' + text + ')').each(function(i, item) {
 matches.push( item );
}
Tharsan
He said he does not have any specific text to search for.
TM
+3  A: 
$("#my_div *").filter(function()
{
     var $this = $(this);
     return $this.children().length == 0 && $.trim($this.text()).length > 0;
})

This version will not return parent elements that contains the elements having texts, only the last level elements.

May not be the fastest but works quite well on StackOverflow homepage :)

Vincent Robert
From my testing, this was the solution that returned only the elements containing text, not their parents as well.Thanks!!!
Tim Sheiner
Good solution, simpler and cleaner than mine :)
TM
A: 

Would any of these options work to find form inputs that have no value? Or say a value that is an empty string?

Suzan