Home > Net >  Why does my callback become undefined using JavaScript
Why does my callback become undefined using JavaScript

Time:10-06

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>

CodePudding user response:

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>

  • Related