2

I am trying to conditionally remove a class from an HTML string that is built within a JS function.

Note that in the live project, the values in the table and the value in the rows variable change based on an AJAX call. Here, using hard coded values is sufficient to demonstrate this issue.

Why isn't the colorful class being removed?

var rows = 2;
var table = "<table class=\"colorful\"><thead><tr>column 1</tr></thead><tbody><tr><td>A</td></tr><tr><td>B</td></tr></tbody></table>";

if (rows <= 2) {
	$(".colorful", $(table).context).removeClass("colorful");
}

$("body").append(table);
.colorful {
  color: red;
  font-size: x-large;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

0

4 Answers 4

1

Your "table" is still a String, not a DOM element and not part of the DOM tree yet, so your attempt to select it with jQuery $(".colorful" ...) can't succeed.

For my example, I'm renaming table to tableString to distinguish it from the tableElement I'll create.
You can create a detached element from that String using jQuery:
var tableElement = $(tableString);
Then you can remove the class (as a class, not a string) from the element if your condition is met.

Doing it in this order, before you append the table to the DOM, avoids brief flashes of style changes.

var rows = 2;
// We've somehow acquired a string representing a table
var tableString = '<table class="colorful">'
                + '<thead><tr>column 1</tr></thead>'
                + '<tbody><tr><td>A</td></tr>'
                + '<tr><td>B</td></tr></tbody></table>';

// jQuery can parse that string and create a DOM element
// (or in this case a subtree) from it
var tableElement = $(tableString);

// Now you can manipulate it just like a selected node,
// even though it's not attached to the page DOM yet.
if (rows <= 2) {
    tableElement.removeClass('colorful');
}

// Finally, attach it when you're all done making changes.
$("body").append(tableElement);
.colorful {
  color: red;
  font-size: x-large;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Sign up to request clarification or add additional context in comments.

1 Comment

I really appreciate the explanation you provided. The part about a "detached element" is particularly helpful.
1

Because the table hasn't been appended to the DOM yet.

If you move $("body").append(table) to before your class removal, it will work as expected:

var rows = 2;
var table = "<table class=\"colorful\"><thead><tr>column 1</tr></thead><tbody><tr><td>A</td></tr><tr><td>B</td></tr></tbody></table>";

$("body").append(table);

if (rows <= 2) {
  $(".colorful", $(table).context).removeClass("colorful");
}
.colorful {
  color: red;
  font-size: x-large;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Comments

1

Basically your main problem is that you can't target an element that is not on the DOM yet. One solution is to append it to the body first and then target it to remove the class as the other answer shown. But in this particular case, I prefer to append the element in his final state to the DOM, something like this:

var rows = 2;
var tableClass = "";

if (rows > 2)
    tableClass = "colorful";
    
var table = "<table class=\"" + tableClass + "\"><thead><tr>column 1</tr></thead><tbody><tr><td>A</td></tr><tr><td>B</td></tr></tbody></table>";

$("body").append(table);
.colorful {
  color: red;
  font-size: x-large;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

In the case your HTML string comes from another source and you can't manually customize it, maybe you can use String.replace() to remove it:

var rows = 2;
var table = "<table class=\"colorful\"><thead><tr>column 1</tr></thead><tbody><tr><td>A</td></tr><tr><td>B</td></tr></tbody></table>";

if (rows <= 2)
    table = table.replace("colorful", "");

$("body").append(table);
.colorful {
  color: red;
  font-size: x-large;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Comments

0

If you have access to the html that will be added you should edit that. Here is an example of how to do that:

const helperDiv = document.createElement("div");

function removeClass(html, classToRemove) {
  helperDiv.innerHTML = html;
  for (var dom of helperDiv.querySelectorAll(`.${classToRemove}`)) dom.classList.remove(classToRemove);
  return helperDiv.innerHTML;
}

console.log(removeClass("<div class='colorful'></div>", "colorful"));

If you don't have access, you could change the CSS so that it will not display the new element. You could also use an animation to keep track of each element that gets added.

document.body.addEventListener("webkitAnimationEnd", onAnimationEnd);
document.body.addEventListener("animationend", onAnimationEnd);

function onAnimationEnd(event) {
  if (event.animationName === "hidden-listener") {
    console.log(`Element with id ${event.target.id} was added`);
  }
}

setTimeout(function() {
  document.querySelector("#item1").innerHTML = "<div id='item2' class='colorful'></div>";
}, 2500);
body {
  height: 100%;
}

.colorful {
  animation: hidden-listener 0.01s ease-in-out 0s 1 normal forwards running;
}

@keyframes hidden-listener {
  from {
    opacity: 0.01;
  }
  to {
    opacity: 0;
  }
}
<div id="item1" class='colorful'></div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.