Reputation: 2044
I need to execute a function on an element that may or may not exist in the DOM, using a querySelector
(not querySelectorAll
, because there will be at most one such element). The most elegant solution I can devise is:
(function (element) {
if (element) {
[business logic of the function]
}
}(document.querySelector([css selector])));
The goal would be not to call the function at all if the querySelector
doesn't return an element. (querySelector
returns null
if no matching element is found.)
My original question lacked clear criteria, and my objections to the responses resulted in the question being closed as being opinion-based. Here's the criteria:
I want to solve this without having to declare a variable external to the routine, e.g., not:
let x = document.querySelector([css selector]);
if (x) {
[business logic on x]
};
I'd like something as elegant as document.querySelectorAll, which returns an iterable NodeList (or null) that does not require testing on the returned data before performing work on it. I.e.,
document.querySelectorAll([css selector]).forEach(function (element) {
[business logic using element]
});
querySelectorAll
is overkill here, because I'll have 1 returned element at most, and if nothing is returned, no business logic will be run.
At present, the only way I can see to do it is: pass the returned value to the function, and check in the function whether the return is not falsy before proceeding with the work of the function.
Is there an elegant way not to call the function if the return of the querySelector
is not an element?
Again, I don't want to use querySelectorAll
, since there will be at most one element that matches the querySelector
. The beauty of the current solution is that it relies on an anonymous function, and there's no need to create an explicit variable (with var
or let
), since the function provides a param for passing.
Upvotes: -1
Views: 1411
Reputation: 665343
I don't want to use
querySelectorAll
, since there will be at most one element that matches the selector
You may want to reconsider this stance. This is a perfect use case for querySelectorAll
: you want to get a collection with all the elements in the document that match the selector. If your document contains at most one such element, that's ok, and you'll get a collection of either 0 or 1 elements - that doesn't change the fact that this is just a special case of getting N elements.
Using this approach, the code is short and simple:
document.querySelectorAll(…).forEach(element => {
… // business logic
});
or
for (const element of document.querySelectorAll(…)) {
… // business logic
}
If it would look weird to have the logic executed multiple times, add a comment to explain that the selector matches either 0 or 1 elements.
That said, I don't see anything wrong with
(element => {
if (!element) return;
… // business logic
})(document.querySelector(…));
If you really need a special syntax for this, write your own helper function or have a look at discussions for some pipeline operators, which proposed optional pipelining like
document.querySelector(…) ?> (element => {
… // business logic
});
You would need to write your own transpiler plugin or macro for that, though.
Upvotes: 1
Reputation: 2044
The method that Đinh-carabus proposed in the comments above is likely closest to the solution I'm seeking, but only if abstracted into a function that can be called as needed, to wit:
function myQuerySelector(selector, func) {
Array.from(document.querySelector(selector)).filter(Boolean).forEach(func);
}
// trivial use case:
myQuerySelector('body', function (element) {
console.log(element);
});
A less complex solution that could be used without calling an original function would be preferable, but this solution may have general value, so I'm posting it here as a solution.
Upvotes: 0
Reputation: 782295
You can assign the variable in the if
statement.
let element;
if (element = document.querySelector("selector")) {
// do something with element
}
Upvotes: 0