knot22
knot22

Reputation: 2768

manipulate HTML string using jQuery before it is appended to DOM

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>

Upvotes: 2

Views: 253

Answers (4)

Stephen P
Stephen P

Reputation: 14810

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>

Upvotes: 1

nick zoum
nick zoum

Reputation: 7315

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>

Upvotes: 0

Shidersz
Shidersz

Reputation: 17190

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>

Upvotes: 1

Obsidian Age
Obsidian Age

Reputation: 42334

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>

Upvotes: 1

Related Questions