views:

85

answers:

4

On user click I would like to get a list of all elements that resides at the clicked point.

For example, if user clicks on Hello here:

<div><span>Hello<span></div>

I would like to get the following list:

  • <span> element
  • <div> element
  • <body> element
  • <html> element

What would be the easiest method to get these elements ?

+1  A: 

The jQuery parents() function can do this for you.

To attach a click event to all span tags, for example:

$("span").click(function() {
    var parents = "";
    $(this).parents().map(function () {
        parents = parents + " " + this.tagName;
    })
    alert(parents);
});
Jeff
I'm not looking for parents. Please see my comments and counterexample above.
Misha Moroshko
A: 

use parent method to get parent of the current tag recursively or in cycle:

var parentTag = $(this).parent().get(0).tagName;
zaynyatyi
+8  A: 

EDIT: Based on clarification, I think this is what you mean:

EDIT: As pointed out by @Misha, outerWidth() and outerHeight() should be used in lieu of width() and height() in order to get an accurate range.

Also, if there's nothing to prevent event bubbling on the page, then the click should be placed on the document as it will be much more efficient. Even if some other click handler prevents bubbling, you should still have the click on the document, and just handle it separately from those handler that prevent bubbling.

Example: http://jsfiddle.net/57bVR/3/

$(document).click(function(e) {
    var clickX = e.pageX
        ,clickY = e.pageY
        ,list
        ,$list
        ,offset
        ,range
        ,$body = $('body').parents().andSelf();

    $list = $('body *').filter(function() {
        offset = $(this).offset();
        range = {
            x: [ offset.left,
                offset.left + $(this).outerWidth() ],
            y: [ offset.top,
                offset.top + $(this).outerHeight() ]
        };
        return (clickX >= range.x[0] && clickX <= range.x[1]) && (clickY >= range.y[0] && clickY <= range.y[1])
    });

    $list = $list.add($body);

    list = $list.map(function() {
        return this.nodeName + ' ' + this.className
    }).get();
    alert(list);
    return false;
});​

Original answer:

This will give you an Array of the tag names including the span. Couldn't quite tell if this is what you wanted.

It uses .parents() along with .andSelf() to get the elements, then uses .map() with .get() to create the Array.

Example: http://jsfiddle.net/9cFTG/

var list;

$('span').click(function() {
    list = $(this).parents().andSelf().map(function() {
        return this.nodeName;
    }).get();
    alert(list);
});​

If you just wanted the elements, not the tag names, get rid of .map() and .get().

Or if you wanted to join the Array into a String using some sort of separator, just add .join(" ") after .get(), placing your separator inside the quotes.

patrick dw
I'm not looking for parents. Look here: http://jsfiddle.net/9cFTG/1/ `.a` and `.b` are not parents, but if user clicks on the intersection, I would like to have them both ! (sorry, fixed the link)
Misha Moroshko
@Misha - So what you're looking for is a list of all the elements that are positioned via CSS at the point on the screen where the click took place? It would seem that you would need to loop through *every* element on the page and get its position and size, and compare it to the click position. Are you sure that's what you want? Or can you limit it to certain classes of elements?
patrick dw
I want let user to change elements colors on the page. When he clicks on some element, in case of ambiguity, he should be able to choose which element he meant.
Misha Moroshko
@Misha - Give me a couple minutes.
patrick dw
With pleasure :)
Misha Moroshko
@Misha - Before I post it, I want to see if this is what you mean. http://jsfiddle.net/57bVR/1/ It does not include the `<body>` and `<html>` elements. If you want to include those, we could probably just add them to the set manually since they should always be included.
patrick dw
Looks great, thanks a lot !!
Misha Moroshko
@Misha - You're welcome. I posted the answer, and added in the `<HTML>` and `<BODY>`. Also, if there will not be any elements added dynamically to the page, it would probably be good to cache `$('body *')` in a variable so you're not having traverse the DOM every time. :o)
patrick dw
Patrick, thank you very much for your efforts !
Misha Moroshko
One last comment: I think it is better to use `outerWidth()` and `outerHeight()` to include also the possible borders.
Misha Moroshko
@Misha - Excellent point! Since the values returned from `offset()` include the border, if you don't use `outerWidth/Height`, then the "range" will be off, and clicks on the right/bottom edges (even inside the borders) won't register. One more thing. As long as you don't have any other 'click' events on the page that prevent event bubbling, it will be *much* more efficient to place the `click` event on the `document`, as in `$(document).click(...`. Not sure why I didn't mention it before. http://jsfiddle.net/57bVR/3/ I'll update my answer with both changes for future reference. :o)
patrick dw
A: 

hi Misha

Try something like this

$('span').click(function() {
 var parents = $(this).parents();
 for(var i = 0; i < parents.length; i++){
  console.log($(parents[i]).get(0).tagName)
 }
});

check the live demo

http://jsfiddle.net/sdA44/1/

JapanPro