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.
3 Answers 3
You can assign the variable in the if
statement.
let element;
if (element = document.querySelector("selector")) {
// do something with element
}
5 Comments
for
, you can't put the variable declaration directly in the if
condition.for (let element = document.querySelector("selector"); element; element = null) { ... }
? shudderswitch(true) { case condition1: ... case condition2: ... }
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.
1 Comment
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.
5 Comments
if
statement in there instead of this hard-to-understand syntax.new Array
[...document.querySelectorAll('div')].forEach(function(element) { console.log(element); });
document.querySelectorAll('div').forEach(function (element) { console.log(element); });
There's no need to spread the results of querySelectorAll
, as it returns an iterable nodelist that .forEach
can be called on directly.Explore related questions
See similar questions with these tags.
document.querySelector(...)?.someMethod(...)
.document.querySelectorAll([selector]).forEach((element) => { [business logic] });
If nothing is returned, the function is not invoked. I'm essentially seeking the same kind of elegance forquerySelector
.[document.querySelector([selector])].filter(Boolean).forEach(function(element) { [business logic] })
:)