1

I am working on a page that needs to insert a script into the DOM and evaluate it. This script contains a class that will instantiate some callbacks to particular elements that are also being inserted into the page.

If i do this process for one event handler, everything works as expected. However when i do this for a second event handler the first event handler stops working

function processJson(outputJson) {
  for (var i in outputJson) {
    let divIDForPlot = "plot_" + i;
    document.getElementById("parent").innerHTML += "<div id='" + divIDForPlot + "'></div>";

    let item = outputJson[i];
    let type = item["outputType"];

    if (type == "plot") {
      processPlot(divIDForPlot, item);
    } else if (type == "table") {

    }
    // break;

  }
}


function processPlot(elementId, plotData) {

  let additionalHtml = plotData["AdditionalHtml"];

  document.getElementById(elementId).innerHTML = additionalHtml;
  let script = plotData["script"];
  let outputData = " ";
  let dataString = "var data = " + JSON.stringify(outputData) + ";";
  let finalScript = dataString + "\n" + script;

  var s = document.createElement('script');
  s.type = 'text/javascript';
  try {
    s.appendChild(document.createTextNode(finalScript));
    document.getElementById(elementId).appendChild(s);
  } catch (e) {
    s.text = finalScript;
    document.getElementById(elementId).appendChild(s);
  }
}


function run() {
  processJson(dataJson["output"]);
}




let dataJson = {
  "output": [{

      "outputType": "plot",
      "AdditionalHtml": "<div id='revenue_trend'></div> <div class='control-row' >Periodicity:<select  id='revenue_trend_periodicity'></select>Measure:<select id = 'revenue_trend_measure' ></select ></div > ",
      "script": "class RevenueTrend{constructor(e){this.data=e,this.periodicitySelector=document.getElementById('revenue_trend_periodicity'),this.measureSelector=document.getElementById('revenue_trend_measure'),this.periodicitySelector.addEventListener('change',()=>{console.log('periodicitySelector changed')},!1),this.measureSelector.addEventListener('change',()=>{console.log('measureSelector changed')},!1),this.#b(['monthly','weekly'],this.periodicitySelector),this.#b(['revenue','profit','margin'],this.measureSelector)}updateBySelector=()=>{this.#a(this.periodicitySelector.value,this.measureSelector.value)};#a=(e,t)=>{var r=this.data.data[t][e];let i=this.data.layout[t]};#b=(e,t)=>{for(var r=0;r<e.length;r++){var i=document.createElement('option');i.text=e[r],t.appendChild(i)}}}let revenue_trend = new RevenueTrend(data);"
    },
    {

      "outputType": "plot",
      "AdditionalHtml": "<div id='revenue_trend2'></div> <div class='control-row' >Periodicity:<select  id='revenue_trend_periodicity2'></select>Measure:<select id = 'revenue_trend_measure2' ></select ></div > ",
      "script": "class RevenueTrend2{constructor(e){this.data=e,this.periodicitySelector=document.getElementById('revenue_trend_periodicity2'),this.measureSelector=document.getElementById('revenue_trend_measure2'),this.periodicitySelector.addEventListener('change',()=>{console.log('periodicitySelector2 changed')},!1),this.measureSelector.addEventListener('change',()=>{console.log('measureSelector2 changed')},!1),this.#b(['monthly','weekly'],this.periodicitySelector),this.#b(['revenue','profit','margin'],this.measureSelector)}updateBySelector=()=>{this.#a(this.periodicitySelector.value,this.measureSelector.value)};#a=(e,t)=>{};#b=(e,t)=>{for(var r=0;r<e.length;r++){var i=document.createElement('option');i.text=e[r],t.appendChild(i)}}}let revenue_trend2 = new RevenueTrend2(data);"
    }
  ]
};

run()
<!DOCTYPE html>
<html>

<head>
</head>

<body>
  <div id="parent"></div>
</body>

</html>

9
  • 1
    It's going to be extremely difficult to figure out what's going on with an minimal reproducible example You should be able to create something similar with Stack Snippets. Commented Sep 29, 2022 at 13:17
  • 1
    Where’s your event handlers? Commented Oct 1, 2022 at 13:34
  • 1
    @DanielA.White The event handlers are defined in the script that I am inserting Commented Oct 1, 2022 at 13:40
  • 4
    Duplicate of stackoverflow.com/questions/595808/… - your problem is running document.getElementById("parent").innerHTML += … multiple times Commented Oct 1, 2022 at 15:26
  • 2
    Btw, don't use for…in enumerations on arrays! Commented Oct 1, 2022 at 15:28

1 Answer 1

3
+200

The problem here is with this line

document.getElementById("parent").innerHTML += "<div id='" + divIDForPlot + "'></div>";

You need use appendChild to maintain the previous element's event listeners.

You can learn more about innerHTML vs appendChild here

function processJson(outputJson) {
  for (var i in outputJson) {
    let divIDForPlot = "plot_" + i;
    const plotElement = document.createElement('div');
    plotElement.id = divIDForPlot;
    document.getElementById("parent").appendChild(plotElement);

    let item = outputJson[i];
    let type = item["outputType"];

    if (type == "plot") {
      processPlot(divIDForPlot, item);
    } else if (type == "table") {

    }
    // break;

  }
}


function processPlot(elementId, plotData) {

  let additionalHtml = plotData["AdditionalHtml"];

  document.getElementById(elementId).innerHTML = additionalHtml;
  let script = plotData["script"];
  let outputData = " ";
  let dataString = "var data = " + JSON.stringify(outputData) + ";";
  let finalScript = dataString + "\n" + script;

  var s = document.createElement('script');
  s.type = 'text/javascript';
  try {
    s.appendChild(document.createTextNode(finalScript));
    document.getElementById(elementId).appendChild(s);
  } catch (e) {
    s.text = finalScript;
    document.getElementById(elementId).appendChild(s);
  }
}


function run() {
  processJson(dataJson["output"]);
}




let dataJson = {
  "output": [{

      "outputType": "plot",
      "AdditionalHtml": "<div id='revenue_trend'></div> <div class='control-row' >Periodicity:<select  id='revenue_trend_periodicity'></select>Measure:<select id = 'revenue_trend_measure' ></select ></div > ",
      "script": "class RevenueTrend{constructor(e){this.data=e,this.periodicitySelector=document.getElementById('revenue_trend_periodicity'),this.measureSelector=document.getElementById('revenue_trend_measure'),this.periodicitySelector.addEventListener('change',()=>{console.log('periodicitySelector changed')},!1),this.measureSelector.addEventListener('change',()=>{console.log('measureSelector changed')},!1),this.#b(['monthly','weekly'],this.periodicitySelector),this.#b(['revenue','profit','margin'],this.measureSelector)}updateBySelector=()=>{this.#a(this.periodicitySelector.value,this.measureSelector.value)};#a=(e,t)=>{var r=this.data.data[t][e];let i=this.data.layout[t]};#b=(e,t)=>{for(var r=0;r<e.length;r++){var i=document.createElement('option');i.text=e[r],t.appendChild(i)}}}let revenue_trend = new RevenueTrend(data);"
    },
    {

      "outputType": "plot",
      "AdditionalHtml": "<div id='revenue_trend2'></div> <div class='control-row' >Periodicity:<select  id='revenue_trend_periodicity2'></select>Measure:<select id = 'revenue_trend_measure2' ></select ></div > ",
      "script": "class RevenueTrend2{constructor(e){this.data=e,this.periodicitySelector=document.getElementById('revenue_trend_periodicity2'),this.measureSelector=document.getElementById('revenue_trend_measure2'),this.periodicitySelector.addEventListener('change',()=>{console.log('periodicitySelector2 changed')},!1),this.measureSelector.addEventListener('change',()=>{console.log('measureSelector2 changed')},!1),this.#b(['monthly','weekly'],this.periodicitySelector),this.#b(['revenue','profit','margin'],this.measureSelector)}updateBySelector=()=>{this.#a(this.periodicitySelector.value,this.measureSelector.value)};#a=(e,t)=>{};#b=(e,t)=>{for(var r=0;r<e.length;r++){var i=document.createElement('option');i.text=e[r],t.appendChild(i)}}}let revenue_trend2 = new RevenueTrend2(data);"
    }
  ]
};

run()
<!DOCTYPE html>
<html>

<head>
</head>

<body>
  <div id="parent"></div>
</body>

</html>

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

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.