A simple function that removes empty or tags containing just ' '
I've written a function that should get rid of empty p, span, etc tags and those with just ' ' and am looking for ways to improve it. My original solution was very 'wet', but I've managed to come up with a drier solution.
The Original HTML:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='test'>
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
My Original Solution:
/*
How to make this drier?
ORIGINAL UNCLEAN SOLUTION
*/
var ps = document.getElementsByTagName('p'),
spans = document.getElementsByTagName('span'),
strongs = document.getElementsByTagName('strong');
for (let el of ps) {
if (el.innerHTML == ' ') { // can't also include if '' at this stage
el.parentNode.removeChild(el);
}
}
for (let el of spans) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
for (let el of strongs) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
for (let el of ps) {
if (el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
My 'drier' solution:
/*
MY CLEANER SOLUTION
*/
var ps = document.getElementsByTagName('p'),
spans = document.getElementsByTagName('span'),
strongs = document.getElementsByTagName('strong');
for (let el of ps) {
cleaner(el);
}
for (let el of spans) {
cleaner(el);
}
for (let el of strongs) {
cleaner(el);
}
function cleaner(el) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
Would someone mind quickly running over both solutions and verifying that my 2nd solution is best? Also, I wonder whether that could be improved, or whether anyone has any better ideas for a solution? Thanks for the help here - for brevity, I'm looking at writing concise but also clear code.
javascript strings html ecmascript-6
add a comment |
I've written a function that should get rid of empty p, span, etc tags and those with just ' ' and am looking for ways to improve it. My original solution was very 'wet', but I've managed to come up with a drier solution.
The Original HTML:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='test'>
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
My Original Solution:
/*
How to make this drier?
ORIGINAL UNCLEAN SOLUTION
*/
var ps = document.getElementsByTagName('p'),
spans = document.getElementsByTagName('span'),
strongs = document.getElementsByTagName('strong');
for (let el of ps) {
if (el.innerHTML == ' ') { // can't also include if '' at this stage
el.parentNode.removeChild(el);
}
}
for (let el of spans) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
for (let el of strongs) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
for (let el of ps) {
if (el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
My 'drier' solution:
/*
MY CLEANER SOLUTION
*/
var ps = document.getElementsByTagName('p'),
spans = document.getElementsByTagName('span'),
strongs = document.getElementsByTagName('strong');
for (let el of ps) {
cleaner(el);
}
for (let el of spans) {
cleaner(el);
}
for (let el of strongs) {
cleaner(el);
}
function cleaner(el) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
Would someone mind quickly running over both solutions and verifying that my 2nd solution is best? Also, I wonder whether that could be improved, or whether anyone has any better ideas for a solution? Thanks for the help here - for brevity, I'm looking at writing concise but also clear code.
javascript strings html ecmascript-6
Does the code at the question produce the expected result? Should<p></p>
be a child element of#test
following execution of the code? Can you include the expected resulting HTML at the question?
– guest271314
yesterday
add a comment |
I've written a function that should get rid of empty p, span, etc tags and those with just ' ' and am looking for ways to improve it. My original solution was very 'wet', but I've managed to come up with a drier solution.
The Original HTML:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='test'>
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
My Original Solution:
/*
How to make this drier?
ORIGINAL UNCLEAN SOLUTION
*/
var ps = document.getElementsByTagName('p'),
spans = document.getElementsByTagName('span'),
strongs = document.getElementsByTagName('strong');
for (let el of ps) {
if (el.innerHTML == ' ') { // can't also include if '' at this stage
el.parentNode.removeChild(el);
}
}
for (let el of spans) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
for (let el of strongs) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
for (let el of ps) {
if (el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
My 'drier' solution:
/*
MY CLEANER SOLUTION
*/
var ps = document.getElementsByTagName('p'),
spans = document.getElementsByTagName('span'),
strongs = document.getElementsByTagName('strong');
for (let el of ps) {
cleaner(el);
}
for (let el of spans) {
cleaner(el);
}
for (let el of strongs) {
cleaner(el);
}
function cleaner(el) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
Would someone mind quickly running over both solutions and verifying that my 2nd solution is best? Also, I wonder whether that could be improved, or whether anyone has any better ideas for a solution? Thanks for the help here - for brevity, I'm looking at writing concise but also clear code.
javascript strings html ecmascript-6
I've written a function that should get rid of empty p, span, etc tags and those with just ' ' and am looking for ways to improve it. My original solution was very 'wet', but I've managed to come up with a drier solution.
The Original HTML:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='test'>
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
My Original Solution:
/*
How to make this drier?
ORIGINAL UNCLEAN SOLUTION
*/
var ps = document.getElementsByTagName('p'),
spans = document.getElementsByTagName('span'),
strongs = document.getElementsByTagName('strong');
for (let el of ps) {
if (el.innerHTML == ' ') { // can't also include if '' at this stage
el.parentNode.removeChild(el);
}
}
for (let el of spans) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
for (let el of strongs) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
for (let el of ps) {
if (el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
My 'drier' solution:
/*
MY CLEANER SOLUTION
*/
var ps = document.getElementsByTagName('p'),
spans = document.getElementsByTagName('span'),
strongs = document.getElementsByTagName('strong');
for (let el of ps) {
cleaner(el);
}
for (let el of spans) {
cleaner(el);
}
for (let el of strongs) {
cleaner(el);
}
function cleaner(el) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
Would someone mind quickly running over both solutions and verifying that my 2nd solution is best? Also, I wonder whether that could be improved, or whether anyone has any better ideas for a solution? Thanks for the help here - for brevity, I'm looking at writing concise but also clear code.
javascript strings html ecmascript-6
javascript strings html ecmascript-6
edited yesterday
Sᴀᴍ Onᴇᴌᴀ
8,42261854
8,42261854
asked yesterday
user8758206
1863
1863
Does the code at the question produce the expected result? Should<p></p>
be a child element of#test
following execution of the code? Can you include the expected resulting HTML at the question?
– guest271314
yesterday
add a comment |
Does the code at the question produce the expected result? Should<p></p>
be a child element of#test
following execution of the code? Can you include the expected resulting HTML at the question?
– guest271314
yesterday
Does the code at the question produce the expected result? Should
<p></p>
be a child element of #test
following execution of the code? Can you include the expected resulting HTML at the question?– guest271314
yesterday
Does the code at the question produce the expected result? Should
<p></p>
be a child element of #test
following execution of the code? Can you include the expected resulting HTML at the question?– guest271314
yesterday
add a comment |
4 Answers
4
active
oldest
votes
You can use querySelectorAll to simplify your code further:
var elements = document.querySelectorAll('p, span, strong'),
for (let el of elements) {
cleaner(el);
}
add a comment |
Beside suggested improvements:
If
<p> </p>
is an empty element to you, then change yourcleaner()
:
function cleaner(el) {
if (el.innerHTML.match(/^s+$/) !== null) {
el.parentNode.removeChild(el);
}
}
You might need to consider going recursive towards elements that have been emptied because of your cleaning procedure.
[Edit] I'm used to verbal function names (a best practice to follow), so I would suggest using
clean
orremove
instead ofcleaner
.
New contributor
add a comment |
There is a bug
You need to run the script several times to remove all empty elements.
Two points
You say remove empty tags that contain
""
or a single space" "
. Does that include" "
or" "
two or more spaces. What about other white space characters?
Your element removal is order dependent because you use
getElementsByTagName
which returns a live list.
Consider the html
<p><span></span></p>
You first check all thep
tags which fail the empty test, then you test thespan
tags which passes and you get<p></p>
which is, by your definition, empty and should have been removed.
On the other hand the html
<span><p></p></span>
will first remove thep
then remove thespan
.
The removal process is order dependent. Not what your question indicates.
Changes
For the first point you could use element.textContent
to check for empty elements. It will ignore the HTML and convert the
to a space for you. You could even use element.textContent.trim()
and thus get all blank elements (like the pseudo-class :blank
(Which has very limited support FF only))
This also covers the second point.
Example Mark and remove
To reduce the DOM calls you can mark and remove deleting the marked elements only.
const isNotMarked = el => {
while (el && el.parentNode && !el.parentNode.marked) {
el = el.parentNode;
if (el.marked) { return false }
}
return true;
}
[...document.querySelectorAll("span, p, strong")]
.filter(el => el.textContent.trim() === "" && isNotMarked(el) ? el.marked = true : false)
.forEach(el => el.parentNode.removeChild(el));
Example simple brute force
Mark and remove saves you attempting to delete already deleted elements but you may not care, as the shorter form, is a two liner, and thus could be argued to be the better solution.
document.querySelectorAll("span, p, strong")
.forEach(el => el.textContent.trim() === "" && el.parentNode.removeChild(el))
The following snippet shows the HTML after using your function and then the two example functions
/*=================================================================================
OP ver modified for example
=================================================================================*/
var ps = cleaned.getElementsByTagName('p'),
spans = cleaned.getElementsByTagName('span'),
strongs = cleaned.getElementsByTagName('strong');
for (let el of ps) { cleaner(el); }
for (let el of spans) { cleaner(el); }
for (let el of strongs) { cleaner(el); }
function cleaner(el) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
content.textContent = cleaned.innerHTML;
/*=================================================================================
Mark and remove
=================================================================================*/
const isNotMarked = el => {
while (el && el.parentNode && !el.parentNode.marked) {
el = el.parentNode;
if (el.marked) { return false }
}
return true;
}
[...cleanerClean.querySelectorAll("span, p, strong")]
.filter(el => el.textContent.trim() === "" && isNotMarked(el) ? el.marked = true : false)
.forEach(el => el.parentNode.removeChild(el));
contentA.textContent = cleanerClean.innerHTML;
/*=================================================================================
Brute force remove
=================================================================================*/
simplerClean.querySelectorAll("span, p, strong")
.forEach(el => el.textContent.trim() === "" && el.parentNode.removeChild(el))
contentB.textContent = simplerClean.innerHTML;
#content {
display: block;
}
<div id="cleaned" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Original OPs script & Resulting HTML</legend>
<code id = "content"></code>
</fieldset>
<div id="cleanerClean" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Mark and remove</legend>
<code id = "contentA"></code>
</fieldset>
<div id="simplerClean" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Brute force remove</legend>
<code id = "contentB"></code>
</fieldset>
add a comment |
I support the main aspect of Carra's answer (i.e. using querySelectorAll()
). In addition, a functional approach can be used, since the function cleaner
is applied to each element. For that, utilize Array.prototype.forEach()
.
elements.forEach(cleaner);
That way, there is no need to set up an iterator variable (e.g. el
in the for...of
loop just to pass it to the function. The function will receive the element as the first parameter each time it is called - once for each element in the collection.
Additionally, since ecmascript-6 features like for...of
and let
are used, others like const
can be used (e.g. for any variable that doesn't need to be re-assigned). One could also use arrow functions if desired.
And it would be a good habit to use the strict equality comparison (i.e. ===
) when comparing the innerHTML properties with the strings.
function cleaner(el) {
if (el.innerHTML === ' ' || el.innerHTML === '') {
el.parentNode.removeChild(el);
}
}
const elements = document.querySelectorAll('p, span, strong');
elements.forEach(cleaner);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='test'>
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210883%2fa-simple-function-that-removes-empty-or-tags-containing-just-nbsp%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can use querySelectorAll to simplify your code further:
var elements = document.querySelectorAll('p, span, strong'),
for (let el of elements) {
cleaner(el);
}
add a comment |
You can use querySelectorAll to simplify your code further:
var elements = document.querySelectorAll('p, span, strong'),
for (let el of elements) {
cleaner(el);
}
add a comment |
You can use querySelectorAll to simplify your code further:
var elements = document.querySelectorAll('p, span, strong'),
for (let el of elements) {
cleaner(el);
}
You can use querySelectorAll to simplify your code further:
var elements = document.querySelectorAll('p, span, strong'),
for (let el of elements) {
cleaner(el);
}
answered yesterday
Carra
21415
21415
add a comment |
add a comment |
Beside suggested improvements:
If
<p> </p>
is an empty element to you, then change yourcleaner()
:
function cleaner(el) {
if (el.innerHTML.match(/^s+$/) !== null) {
el.parentNode.removeChild(el);
}
}
You might need to consider going recursive towards elements that have been emptied because of your cleaning procedure.
[Edit] I'm used to verbal function names (a best practice to follow), so I would suggest using
clean
orremove
instead ofcleaner
.
New contributor
add a comment |
Beside suggested improvements:
If
<p> </p>
is an empty element to you, then change yourcleaner()
:
function cleaner(el) {
if (el.innerHTML.match(/^s+$/) !== null) {
el.parentNode.removeChild(el);
}
}
You might need to consider going recursive towards elements that have been emptied because of your cleaning procedure.
[Edit] I'm used to verbal function names (a best practice to follow), so I would suggest using
clean
orremove
instead ofcleaner
.
New contributor
add a comment |
Beside suggested improvements:
If
<p> </p>
is an empty element to you, then change yourcleaner()
:
function cleaner(el) {
if (el.innerHTML.match(/^s+$/) !== null) {
el.parentNode.removeChild(el);
}
}
You might need to consider going recursive towards elements that have been emptied because of your cleaning procedure.
[Edit] I'm used to verbal function names (a best practice to follow), so I would suggest using
clean
orremove
instead ofcleaner
.
New contributor
Beside suggested improvements:
If
<p> </p>
is an empty element to you, then change yourcleaner()
:
function cleaner(el) {
if (el.innerHTML.match(/^s+$/) !== null) {
el.parentNode.removeChild(el);
}
}
You might need to consider going recursive towards elements that have been emptied because of your cleaning procedure.
[Edit] I'm used to verbal function names (a best practice to follow), so I would suggest using
clean
orremove
instead ofcleaner
.
New contributor
edited yesterday
New contributor
answered yesterday
mrmowji
1214
1214
New contributor
New contributor
add a comment |
add a comment |
There is a bug
You need to run the script several times to remove all empty elements.
Two points
You say remove empty tags that contain
""
or a single space" "
. Does that include" "
or" "
two or more spaces. What about other white space characters?
Your element removal is order dependent because you use
getElementsByTagName
which returns a live list.
Consider the html
<p><span></span></p>
You first check all thep
tags which fail the empty test, then you test thespan
tags which passes and you get<p></p>
which is, by your definition, empty and should have been removed.
On the other hand the html
<span><p></p></span>
will first remove thep
then remove thespan
.
The removal process is order dependent. Not what your question indicates.
Changes
For the first point you could use element.textContent
to check for empty elements. It will ignore the HTML and convert the
to a space for you. You could even use element.textContent.trim()
and thus get all blank elements (like the pseudo-class :blank
(Which has very limited support FF only))
This also covers the second point.
Example Mark and remove
To reduce the DOM calls you can mark and remove deleting the marked elements only.
const isNotMarked = el => {
while (el && el.parentNode && !el.parentNode.marked) {
el = el.parentNode;
if (el.marked) { return false }
}
return true;
}
[...document.querySelectorAll("span, p, strong")]
.filter(el => el.textContent.trim() === "" && isNotMarked(el) ? el.marked = true : false)
.forEach(el => el.parentNode.removeChild(el));
Example simple brute force
Mark and remove saves you attempting to delete already deleted elements but you may not care, as the shorter form, is a two liner, and thus could be argued to be the better solution.
document.querySelectorAll("span, p, strong")
.forEach(el => el.textContent.trim() === "" && el.parentNode.removeChild(el))
The following snippet shows the HTML after using your function and then the two example functions
/*=================================================================================
OP ver modified for example
=================================================================================*/
var ps = cleaned.getElementsByTagName('p'),
spans = cleaned.getElementsByTagName('span'),
strongs = cleaned.getElementsByTagName('strong');
for (let el of ps) { cleaner(el); }
for (let el of spans) { cleaner(el); }
for (let el of strongs) { cleaner(el); }
function cleaner(el) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
content.textContent = cleaned.innerHTML;
/*=================================================================================
Mark and remove
=================================================================================*/
const isNotMarked = el => {
while (el && el.parentNode && !el.parentNode.marked) {
el = el.parentNode;
if (el.marked) { return false }
}
return true;
}
[...cleanerClean.querySelectorAll("span, p, strong")]
.filter(el => el.textContent.trim() === "" && isNotMarked(el) ? el.marked = true : false)
.forEach(el => el.parentNode.removeChild(el));
contentA.textContent = cleanerClean.innerHTML;
/*=================================================================================
Brute force remove
=================================================================================*/
simplerClean.querySelectorAll("span, p, strong")
.forEach(el => el.textContent.trim() === "" && el.parentNode.removeChild(el))
contentB.textContent = simplerClean.innerHTML;
#content {
display: block;
}
<div id="cleaned" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Original OPs script & Resulting HTML</legend>
<code id = "content"></code>
</fieldset>
<div id="cleanerClean" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Mark and remove</legend>
<code id = "contentA"></code>
</fieldset>
<div id="simplerClean" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Brute force remove</legend>
<code id = "contentB"></code>
</fieldset>
add a comment |
There is a bug
You need to run the script several times to remove all empty elements.
Two points
You say remove empty tags that contain
""
or a single space" "
. Does that include" "
or" "
two or more spaces. What about other white space characters?
Your element removal is order dependent because you use
getElementsByTagName
which returns a live list.
Consider the html
<p><span></span></p>
You first check all thep
tags which fail the empty test, then you test thespan
tags which passes and you get<p></p>
which is, by your definition, empty and should have been removed.
On the other hand the html
<span><p></p></span>
will first remove thep
then remove thespan
.
The removal process is order dependent. Not what your question indicates.
Changes
For the first point you could use element.textContent
to check for empty elements. It will ignore the HTML and convert the
to a space for you. You could even use element.textContent.trim()
and thus get all blank elements (like the pseudo-class :blank
(Which has very limited support FF only))
This also covers the second point.
Example Mark and remove
To reduce the DOM calls you can mark and remove deleting the marked elements only.
const isNotMarked = el => {
while (el && el.parentNode && !el.parentNode.marked) {
el = el.parentNode;
if (el.marked) { return false }
}
return true;
}
[...document.querySelectorAll("span, p, strong")]
.filter(el => el.textContent.trim() === "" && isNotMarked(el) ? el.marked = true : false)
.forEach(el => el.parentNode.removeChild(el));
Example simple brute force
Mark and remove saves you attempting to delete already deleted elements but you may not care, as the shorter form, is a two liner, and thus could be argued to be the better solution.
document.querySelectorAll("span, p, strong")
.forEach(el => el.textContent.trim() === "" && el.parentNode.removeChild(el))
The following snippet shows the HTML after using your function and then the two example functions
/*=================================================================================
OP ver modified for example
=================================================================================*/
var ps = cleaned.getElementsByTagName('p'),
spans = cleaned.getElementsByTagName('span'),
strongs = cleaned.getElementsByTagName('strong');
for (let el of ps) { cleaner(el); }
for (let el of spans) { cleaner(el); }
for (let el of strongs) { cleaner(el); }
function cleaner(el) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
content.textContent = cleaned.innerHTML;
/*=================================================================================
Mark and remove
=================================================================================*/
const isNotMarked = el => {
while (el && el.parentNode && !el.parentNode.marked) {
el = el.parentNode;
if (el.marked) { return false }
}
return true;
}
[...cleanerClean.querySelectorAll("span, p, strong")]
.filter(el => el.textContent.trim() === "" && isNotMarked(el) ? el.marked = true : false)
.forEach(el => el.parentNode.removeChild(el));
contentA.textContent = cleanerClean.innerHTML;
/*=================================================================================
Brute force remove
=================================================================================*/
simplerClean.querySelectorAll("span, p, strong")
.forEach(el => el.textContent.trim() === "" && el.parentNode.removeChild(el))
contentB.textContent = simplerClean.innerHTML;
#content {
display: block;
}
<div id="cleaned" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Original OPs script & Resulting HTML</legend>
<code id = "content"></code>
</fieldset>
<div id="cleanerClean" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Mark and remove</legend>
<code id = "contentA"></code>
</fieldset>
<div id="simplerClean" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Brute force remove</legend>
<code id = "contentB"></code>
</fieldset>
add a comment |
There is a bug
You need to run the script several times to remove all empty elements.
Two points
You say remove empty tags that contain
""
or a single space" "
. Does that include" "
or" "
two or more spaces. What about other white space characters?
Your element removal is order dependent because you use
getElementsByTagName
which returns a live list.
Consider the html
<p><span></span></p>
You first check all thep
tags which fail the empty test, then you test thespan
tags which passes and you get<p></p>
which is, by your definition, empty and should have been removed.
On the other hand the html
<span><p></p></span>
will first remove thep
then remove thespan
.
The removal process is order dependent. Not what your question indicates.
Changes
For the first point you could use element.textContent
to check for empty elements. It will ignore the HTML and convert the
to a space for you. You could even use element.textContent.trim()
and thus get all blank elements (like the pseudo-class :blank
(Which has very limited support FF only))
This also covers the second point.
Example Mark and remove
To reduce the DOM calls you can mark and remove deleting the marked elements only.
const isNotMarked = el => {
while (el && el.parentNode && !el.parentNode.marked) {
el = el.parentNode;
if (el.marked) { return false }
}
return true;
}
[...document.querySelectorAll("span, p, strong")]
.filter(el => el.textContent.trim() === "" && isNotMarked(el) ? el.marked = true : false)
.forEach(el => el.parentNode.removeChild(el));
Example simple brute force
Mark and remove saves you attempting to delete already deleted elements but you may not care, as the shorter form, is a two liner, and thus could be argued to be the better solution.
document.querySelectorAll("span, p, strong")
.forEach(el => el.textContent.trim() === "" && el.parentNode.removeChild(el))
The following snippet shows the HTML after using your function and then the two example functions
/*=================================================================================
OP ver modified for example
=================================================================================*/
var ps = cleaned.getElementsByTagName('p'),
spans = cleaned.getElementsByTagName('span'),
strongs = cleaned.getElementsByTagName('strong');
for (let el of ps) { cleaner(el); }
for (let el of spans) { cleaner(el); }
for (let el of strongs) { cleaner(el); }
function cleaner(el) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
content.textContent = cleaned.innerHTML;
/*=================================================================================
Mark and remove
=================================================================================*/
const isNotMarked = el => {
while (el && el.parentNode && !el.parentNode.marked) {
el = el.parentNode;
if (el.marked) { return false }
}
return true;
}
[...cleanerClean.querySelectorAll("span, p, strong")]
.filter(el => el.textContent.trim() === "" && isNotMarked(el) ? el.marked = true : false)
.forEach(el => el.parentNode.removeChild(el));
contentA.textContent = cleanerClean.innerHTML;
/*=================================================================================
Brute force remove
=================================================================================*/
simplerClean.querySelectorAll("span, p, strong")
.forEach(el => el.textContent.trim() === "" && el.parentNode.removeChild(el))
contentB.textContent = simplerClean.innerHTML;
#content {
display: block;
}
<div id="cleaned" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Original OPs script & Resulting HTML</legend>
<code id = "content"></code>
</fieldset>
<div id="cleanerClean" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Mark and remove</legend>
<code id = "contentA"></code>
</fieldset>
<div id="simplerClean" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Brute force remove</legend>
<code id = "contentB"></code>
</fieldset>
There is a bug
You need to run the script several times to remove all empty elements.
Two points
You say remove empty tags that contain
""
or a single space" "
. Does that include" "
or" "
two or more spaces. What about other white space characters?
Your element removal is order dependent because you use
getElementsByTagName
which returns a live list.
Consider the html
<p><span></span></p>
You first check all thep
tags which fail the empty test, then you test thespan
tags which passes and you get<p></p>
which is, by your definition, empty and should have been removed.
On the other hand the html
<span><p></p></span>
will first remove thep
then remove thespan
.
The removal process is order dependent. Not what your question indicates.
Changes
For the first point you could use element.textContent
to check for empty elements. It will ignore the HTML and convert the
to a space for you. You could even use element.textContent.trim()
and thus get all blank elements (like the pseudo-class :blank
(Which has very limited support FF only))
This also covers the second point.
Example Mark and remove
To reduce the DOM calls you can mark and remove deleting the marked elements only.
const isNotMarked = el => {
while (el && el.parentNode && !el.parentNode.marked) {
el = el.parentNode;
if (el.marked) { return false }
}
return true;
}
[...document.querySelectorAll("span, p, strong")]
.filter(el => el.textContent.trim() === "" && isNotMarked(el) ? el.marked = true : false)
.forEach(el => el.parentNode.removeChild(el));
Example simple brute force
Mark and remove saves you attempting to delete already deleted elements but you may not care, as the shorter form, is a two liner, and thus could be argued to be the better solution.
document.querySelectorAll("span, p, strong")
.forEach(el => el.textContent.trim() === "" && el.parentNode.removeChild(el))
The following snippet shows the HTML after using your function and then the two example functions
/*=================================================================================
OP ver modified for example
=================================================================================*/
var ps = cleaned.getElementsByTagName('p'),
spans = cleaned.getElementsByTagName('span'),
strongs = cleaned.getElementsByTagName('strong');
for (let el of ps) { cleaner(el); }
for (let el of spans) { cleaner(el); }
for (let el of strongs) { cleaner(el); }
function cleaner(el) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
content.textContent = cleaned.innerHTML;
/*=================================================================================
Mark and remove
=================================================================================*/
const isNotMarked = el => {
while (el && el.parentNode && !el.parentNode.marked) {
el = el.parentNode;
if (el.marked) { return false }
}
return true;
}
[...cleanerClean.querySelectorAll("span, p, strong")]
.filter(el => el.textContent.trim() === "" && isNotMarked(el) ? el.marked = true : false)
.forEach(el => el.parentNode.removeChild(el));
contentA.textContent = cleanerClean.innerHTML;
/*=================================================================================
Brute force remove
=================================================================================*/
simplerClean.querySelectorAll("span, p, strong")
.forEach(el => el.textContent.trim() === "" && el.parentNode.removeChild(el))
contentB.textContent = simplerClean.innerHTML;
#content {
display: block;
}
<div id="cleaned" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Original OPs script & Resulting HTML</legend>
<code id = "content"></code>
</fieldset>
<div id="cleanerClean" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Mark and remove</legend>
<code id = "contentA"></code>
</fieldset>
<div id="simplerClean" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Brute force remove</legend>
<code id = "contentB"></code>
</fieldset>
/*=================================================================================
OP ver modified for example
=================================================================================*/
var ps = cleaned.getElementsByTagName('p'),
spans = cleaned.getElementsByTagName('span'),
strongs = cleaned.getElementsByTagName('strong');
for (let el of ps) { cleaner(el); }
for (let el of spans) { cleaner(el); }
for (let el of strongs) { cleaner(el); }
function cleaner(el) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
content.textContent = cleaned.innerHTML;
/*=================================================================================
Mark and remove
=================================================================================*/
const isNotMarked = el => {
while (el && el.parentNode && !el.parentNode.marked) {
el = el.parentNode;
if (el.marked) { return false }
}
return true;
}
[...cleanerClean.querySelectorAll("span, p, strong")]
.filter(el => el.textContent.trim() === "" && isNotMarked(el) ? el.marked = true : false)
.forEach(el => el.parentNode.removeChild(el));
contentA.textContent = cleanerClean.innerHTML;
/*=================================================================================
Brute force remove
=================================================================================*/
simplerClean.querySelectorAll("span, p, strong")
.forEach(el => el.textContent.trim() === "" && el.parentNode.removeChild(el))
contentB.textContent = simplerClean.innerHTML;
#content {
display: block;
}
<div id="cleaned" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Original OPs script & Resulting HTML</legend>
<code id = "content"></code>
</fieldset>
<div id="cleanerClean" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Mark and remove</legend>
<code id = "contentA"></code>
</fieldset>
<div id="simplerClean" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Brute force remove</legend>
<code id = "contentB"></code>
</fieldset>
/*=================================================================================
OP ver modified for example
=================================================================================*/
var ps = cleaned.getElementsByTagName('p'),
spans = cleaned.getElementsByTagName('span'),
strongs = cleaned.getElementsByTagName('strong');
for (let el of ps) { cleaner(el); }
for (let el of spans) { cleaner(el); }
for (let el of strongs) { cleaner(el); }
function cleaner(el) {
if (el.innerHTML == ' ' || el.innerHTML == '') {
el.parentNode.removeChild(el);
}
}
content.textContent = cleaned.innerHTML;
/*=================================================================================
Mark and remove
=================================================================================*/
const isNotMarked = el => {
while (el && el.parentNode && !el.parentNode.marked) {
el = el.parentNode;
if (el.marked) { return false }
}
return true;
}
[...cleanerClean.querySelectorAll("span, p, strong")]
.filter(el => el.textContent.trim() === "" && isNotMarked(el) ? el.marked = true : false)
.forEach(el => el.parentNode.removeChild(el));
contentA.textContent = cleanerClean.innerHTML;
/*=================================================================================
Brute force remove
=================================================================================*/
simplerClean.querySelectorAll("span, p, strong")
.forEach(el => el.textContent.trim() === "" && el.parentNode.removeChild(el))
contentB.textContent = simplerClean.innerHTML;
#content {
display: block;
}
<div id="cleaned" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Original OPs script & Resulting HTML</legend>
<code id = "content"></code>
</fieldset>
<div id="cleanerClean" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Mark and remove</legend>
<code id = "contentA"></code>
</fieldset>
<div id="simplerClean" style="display:none;">
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
<fieldset>
<legend>Brute force remove</legend>
<code id = "contentB"></code>
</fieldset>
answered yesterday
Blindman67
7,1461521
7,1461521
add a comment |
add a comment |
I support the main aspect of Carra's answer (i.e. using querySelectorAll()
). In addition, a functional approach can be used, since the function cleaner
is applied to each element. For that, utilize Array.prototype.forEach()
.
elements.forEach(cleaner);
That way, there is no need to set up an iterator variable (e.g. el
in the for...of
loop just to pass it to the function. The function will receive the element as the first parameter each time it is called - once for each element in the collection.
Additionally, since ecmascript-6 features like for...of
and let
are used, others like const
can be used (e.g. for any variable that doesn't need to be re-assigned). One could also use arrow functions if desired.
And it would be a good habit to use the strict equality comparison (i.e. ===
) when comparing the innerHTML properties with the strings.
function cleaner(el) {
if (el.innerHTML === ' ' || el.innerHTML === '') {
el.parentNode.removeChild(el);
}
}
const elements = document.querySelectorAll('p, span, strong');
elements.forEach(cleaner);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='test'>
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
add a comment |
I support the main aspect of Carra's answer (i.e. using querySelectorAll()
). In addition, a functional approach can be used, since the function cleaner
is applied to each element. For that, utilize Array.prototype.forEach()
.
elements.forEach(cleaner);
That way, there is no need to set up an iterator variable (e.g. el
in the for...of
loop just to pass it to the function. The function will receive the element as the first parameter each time it is called - once for each element in the collection.
Additionally, since ecmascript-6 features like for...of
and let
are used, others like const
can be used (e.g. for any variable that doesn't need to be re-assigned). One could also use arrow functions if desired.
And it would be a good habit to use the strict equality comparison (i.e. ===
) when comparing the innerHTML properties with the strings.
function cleaner(el) {
if (el.innerHTML === ' ' || el.innerHTML === '') {
el.parentNode.removeChild(el);
}
}
const elements = document.querySelectorAll('p, span, strong');
elements.forEach(cleaner);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='test'>
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
add a comment |
I support the main aspect of Carra's answer (i.e. using querySelectorAll()
). In addition, a functional approach can be used, since the function cleaner
is applied to each element. For that, utilize Array.prototype.forEach()
.
elements.forEach(cleaner);
That way, there is no need to set up an iterator variable (e.g. el
in the for...of
loop just to pass it to the function. The function will receive the element as the first parameter each time it is called - once for each element in the collection.
Additionally, since ecmascript-6 features like for...of
and let
are used, others like const
can be used (e.g. for any variable that doesn't need to be re-assigned). One could also use arrow functions if desired.
And it would be a good habit to use the strict equality comparison (i.e. ===
) when comparing the innerHTML properties with the strings.
function cleaner(el) {
if (el.innerHTML === ' ' || el.innerHTML === '') {
el.parentNode.removeChild(el);
}
}
const elements = document.querySelectorAll('p, span, strong');
elements.forEach(cleaner);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='test'>
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
I support the main aspect of Carra's answer (i.e. using querySelectorAll()
). In addition, a functional approach can be used, since the function cleaner
is applied to each element. For that, utilize Array.prototype.forEach()
.
elements.forEach(cleaner);
That way, there is no need to set up an iterator variable (e.g. el
in the for...of
loop just to pass it to the function. The function will receive the element as the first parameter each time it is called - once for each element in the collection.
Additionally, since ecmascript-6 features like for...of
and let
are used, others like const
can be used (e.g. for any variable that doesn't need to be re-assigned). One could also use arrow functions if desired.
And it would be a good habit to use the strict equality comparison (i.e. ===
) when comparing the innerHTML properties with the strings.
function cleaner(el) {
if (el.innerHTML === ' ' || el.innerHTML === '') {
el.parentNode.removeChild(el);
}
}
const elements = document.querySelectorAll('p, span, strong');
elements.forEach(cleaner);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='test'>
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
function cleaner(el) {
if (el.innerHTML === ' ' || el.innerHTML === '') {
el.parentNode.removeChild(el);
}
}
const elements = document.querySelectorAll('p, span, strong');
elements.forEach(cleaner);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='test'>
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
function cleaner(el) {
if (el.innerHTML === ' ' || el.innerHTML === '') {
el.parentNode.removeChild(el);
}
}
const elements = document.querySelectorAll('p, span, strong');
elements.forEach(cleaner);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='test'>
<p>text</p>
<p> </p>
<p>text</p>
<p><span>text</span></p>
<p><span></span></p>
<p>text</p>
<p><strong>text</strong></p>
<p></p>
<p> </p>
<p>text</p>
<p><span><strong> </strong></span></p>
<p><span><strong>text</strong></span></p>
<p> </p>
<p><span>text</span></p>
<p></p>
<p><span></span></p>
<p><span> </span></p>
<p><span><strong></strong></span></p>
<p>text</p>
</div>
edited yesterday
answered yesterday
Sᴀᴍ Onᴇᴌᴀ
8,42261854
8,42261854
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210883%2fa-simple-function-that-removes-empty-or-tags-containing-just-nbsp%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Does the code at the question produce the expected result? Should
<p></p>
be a child element of#test
following execution of the code? Can you include the expected resulting HTML at the question?– guest271314
yesterday