Felix Maxime Felix Maxime - 2 months ago 25
jQuery Question

jQuery insertAfter only if not inserted before

So I've got this little script that adds a "Read More" button after divs with the class "only-so-big" if the height of the div exceeds a certain amount.

var allOSB = [];
var mxh = '';

var setResizeVariables = function() {
// Set Variables
allOSB = document.querySelector(".only-so-big :not(.not-these)");

if (allOSB.length > 0) {
mxh = window.getComputedStyle(allOSB[0]).getPropertyValue('max-height');
mxh = parseInt(mxh.replace('px', ''));

// Add read-more button to each OSB section
for (var i = 0; i < allOSB.length; i++) {
var currentOSB = allOSB[i];
var el = document.createElement("button");
el.innerHTML = "Read More";
el.setAttribute("type", "button");
el.setAttribute("class", "read-more hid");

insertAfter(allOSB[i], el);
currentOSB.class += "not-these";
}
}

// Add click function to buttons
var readMoreButtons = document.getElementsByClassName("read-more");
for (var i = 0; i < readMoreButtons.length; i++) {
readMoreButtons[i].addEventListener("click", function() {
revealThis(this);
}, false);
}

// Update buttons so only the needed ones show
updateReadMore();
}


// show only the necessary read-more buttons
function updateReadMore() {
if (allOSB.length > 0) {
for (var i = 0; i < allOSB.length; i++) {
if (allOSB[i].scrollHeight > mxh) {
if (allOSB[i].hasAttribute("style")) {
updateHeight(allOSB[i]);
}
allOSB[i].nextElementSibling.className = "read-more";
} else {
allOSB[i].nextElementSibling.className = "read-more hid";
}
}
}
}

function revealThis(current) {
var el = current.previousElementSibling;
if (el.hasAttribute("style")) {
current.innerHTML = "Read More";
el.removeAttribute("style");
} else {
updateHeight(el);
current.innerHTML = "Show Less";
}
}

function updateHeight(el) {
el.style.maxHeight = el.scrollHeight + "px";
}


function insertAfter(referenceNode, newNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

window.onload = function() {
setResizeVariables();
}

window.onresize = function() {
updateReadMore();
}


HTML/Blade:

<div class="status-body" data-body-status-id="{{ $status->id }}">
<div class="status-body-text only-so-big">{!! $status->body !!}</div>
</div>


However, my current problem is that I'm now calling this function more than once. When this happens, additional "Read more" buttons are added on, leading to multiple buttons. How could it make it so that
insertAfter(allOSB[i], el);
ONLY inserts a new "read more" button if a button with that class doesn't already exist after that div?

Answer Source

You can add a flag to the button to check if you already added the button:

for (var i = 0; i < allOSB.length; i++) {
    var currentOSB = allOSB[i];
    if (currentOSB.hasAttribute("data-button-added")) continue; // check if it's been added already
    var el = document.createElement("button");
    el.innerHTML = "Read More";
    el.setAttribute("type", "button");
    el.setAttribute("class", "read-more hid");
    currentOSB.setAttribute("data-button-added", "1"); // add the flag to the current OSB
    insertAfter(allOSB[i], el);
}

Fiddle: https://jsfiddle.net/5j1vxxxs/2/


This answer was changed extensively. See comments.