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>