2

I'm trying to toggle a paragraph preview/full text and cannot alter the HTML, other than insert a <script> // brute force js </script> block. The element with the paragraph injected dynamically and I have a function which does that successfully, but my problem is toggling my isPreview boolean such that the elm.innerHTML ternary operator line gets the updated value.

I've tried creating an external togglePrview(){} function but that created other problems.

Thoughts on how to achieve this as elegantly as possible?

waitForelm(){...}

let isPreview = true;
waitForElm(".div_with_html").then((elm) => {
  let linkText = isPreview ? "Show more" : "Show less";
  let link = `. . . <a onclick="isPreview = !isPreview">${linkText}</a>`;
  let fullBio = elm.innerHTML;
  let preview = fullBio.substr(0, 450) + link;

  elm.innerHTML = isPreview ? preview : fullBio; // does not get the updated value

});
Kirk Ross
  • 6,413
  • 13
  • 61
  • 104

1 Answers1

0

You should create an element, bind a click event handler to it, and then insert it into the dom, creating a closure that includes the variable. You can't expect the string "...isPreview = !isPreview..." to have access to variables that are not in scope when the code is evaluated at some later date. Strings are strings, they don't create closures, even if the contents of a string happens to match a variable name in the enclosing scope.

let preview = true;
let btn = document.createElement("a");
btn.addEventListener("click", () =>  {
  preview = !preview;
  console.log(preview);
 });
btn.innerHTML = "click me";
document.querySelector("body").appendChild(btn);

See How do JavaScript closures work?

You can, of course, work around this with a global variable so that no closure is required, but you really shouldn't rely on global variables just to produce shorter code:

var preview = true;

document.querySelector("body").innerHTML =
  '<a onclick="preview=!preview; console.log(preview)">click me</a>';
user229044
  • 232,980
  • 40
  • 330
  • 338