Mr_Green
Mr_Green

Reputation: 41840

How do you grab an element relative to an Element instance with a selector?

I am writing a small library where I am in need of selecting a relative element to the targeted element through querySelector method.

For example:

HTML

<div class="target"></div>
<div class="relative"></div>

<!-- querySelector will select only this .target element -->
<div class="target"></div>
<div class="relative"></div>

<div class="target"></div>
<div class="relative"></div>

JavaScript

var target = document.querySelectorAll('.target')[1];

// Something like this which doesn't work actually
var relativeElement = target.querySelector('this + .relative');

In the above example, I am trying to select the .relative class element relative only to the .target element whose value is stored in target variable. No styles should apply to the other .relative class elements.

PS: the selectors can vary. So, I can't use JavaScript's predefined methods like previousElementSibling or nextElementSibling.

I don't need solution in jQuery or other JavaScript libraries.

Upvotes: 2

Views: 3311

Answers (4)

Mr_Green
Mr_Green

Reputation: 41840

I found a way which will work for my library.

I will replace "this " in the querySelector with a unique custom attribute value. Something like this:

Element.prototype.customQuerySelector = function(selector){
    // Adding a custom attribute to refer for selector
    this.setAttribute('data-unique-id', '1');

    // Replace "this " string with custom attribute's value
    // You can also add a unique class name instead of adding custom attribute
    selector = selector.replace("this ", '[data-unique-id="1"] ');

    // Get the relative element
    var relativeElement = document.querySelector(selector);

    // After getting the relative element, the added custom attribute is useless
    // So, remove it
    this.removeAttribute('data-unique-id');

    // return the fetched element
    return relativeElement;
}

var element = document.querySelectorAll('.target')[1];
var targetElement = element.customQuerySelector('this + .relative');

// Now, do anything with the fetched relative element
targetElement.style.color = "red";

Working Fiddle

Upvotes: 1

Sheepy
Sheepy

Reputation: 18016

You cannot. If you insist on using the querySelector of the subject element, the answers is there is no way.

The spec and MDN both says clearly that Element.querySelector must return "a descendant of the element on which it is invoked", and the object element you want does not meet this limitation.

You must go up and use other elements, e.g. document.querySelector, if you want to break out.

You can always override Element.prototype.querySelector to do your biddings, including implementing your own CSS engine that select whatever element you want in whatever syntax you want. I didn't mention this because you will be breaking the assumption of a very important function, easily breaking other libraries and even normal code, or at best slowing them down.

Upvotes: 1

Koustav Ray
Koustav Ray

Reputation: 1142

Well it should be ideally:

var relativeElement = target.querySelector('.relative');

But this will actually try to select something inside the target element. therefore this would only work if your html structure is something like:

<div class="target">
 <div class="relative"></div>
</div>

Your best bet would probably in this case be to use nextElementSibling which I understand is difficult for you to use.

Upvotes: 1

flemcito
flemcito

Reputation: 92

target.querySelector('.relative');

By using querySelector on the target instead of document, you scope the DOM traversal to the target element. It is not entirely clear from your explanation, but by related i assume you mean descendant?

To get all target elements you can use

document.querySelectorAll('.target')

And then iterate the result

Upvotes: 0

Related Questions