I've commented out the config in the new code. You shouldn't see a difference if it was an invalid config anyways. We can always figure out what the actual config should be if you need it to be a certain way.
Normally that would keep them isolated, true. But the template node just puts up whatever is in the template. It exists on the page by itself and can therefore be accessible by any tab and any flow in Node-Red. It doesn't care. Essentially the ui-template makes a global variable/function accessible by anything written in any template node in your instance of Node-Red. Hence why you have to isolate it.
Yes. The first table gets the variable declaration and all references point to it. The function in the second ui-template referenced table.addData(), which would have been a reference to the first table. Which is why the first table got the extra row.
This might actually be caused by how the data is being passed into the tables themselves. If the first table is having an individual row object being passed in, the object is being converted into an array inside the addData() function. If you have an array being passed in (like is what's happening in the second table data inject), that is also getting turned into an array. So it's an array of arrays, which is not something that Tabulator knows what to do with at this point. It knows what to do about an array of objects, but not an array of arrays.
This will be determined outside of your ui-template node by whatever does the injection of the data. Possibly an inject node firing into a function node. Whatever is sending the data into the second ui-template node will dictate when the data is updated.
So, here's what I think might help. Table 1:
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/luxon@3.0.4/build/global/luxon.min.js"></script>
<div id="screener"></div>
<script>
var screenerTable = new Tabulator("#screener", {
height:900,
//textSize : 10,
layout:"fitColumns",
columns:[ //Define Table Columns
{title:"I", field:"note", width:"1%"},
{title:"Coin", field:"currency", hozAlign:"center", width:66},
{title:"Exchange", field:"exchange", hozAlign:"center", width:70},
{title:"UP", field:"percent", hozAlign:"center", width:50,
formatter: function(cell, formatterParams){var value = cell.getValue(); if(value == null) {return ""}; if (value !== null) {if(value >= 0){cell.getElement().style.color ='#609f70'} else {cell.getElement().style.color ='#ff4a68'} return value +'%';}}
},
{title:"W", field:"window", hozAlign:"center", width:"20"
},
{title:"24Hr", field:"change", hozAlign:"center", width:60, formatterParams:{precision:0},
formatter: function(cell, formatterParams){var value = cell.getValue(); if(value == null) {return ""}; if (value !== null) {if(value >= 0){cell.getElement().style.color ='#609f70'} else {cell.getElement().style.color ='#ff4a68'} return value +'%';}}
},
{title:"B", field:"b_coin", hozAlign:"center", width:20, formatter:function(cell, formatterParams, onRendered) {var value = cell.getValue(); if(value == null) {return ""}; return "<span style='color:#2962ff; font-weight:bold;'>" + cell.getValue() + "</span>";}},
{title:"F", field:"f_coin", hozAlign:"center", width:20},
{title:"G", field:"g_coin", hozAlign:"center", width:20},
{title:"Volume", field:"volume", hozAlign:"right", width:100,formatter:"money", formatterParams:{thousand:",", precision:0}},
{title:"Price", field:"price", hozAlign:"right", width:70, formatter:"money", formatterParams:{thousand:","}},
{title:"Time", field:"time", hozAlign:"center", width:100}
],
});
screenerTable.on("rowClick", function(e, row){
var fetchOptions = {
method:'POST',
headers:{'Content-Type':'application/json'},
body:JSON.stringify(screenerTable.getData())
};
fetch("https://red.interscope.link/table-out", fetchOptions)
.catch(function(error){alert(error)});
});
(function(scope){
scope.$watch('msg', function(msg){
if(msg){
screenerTable.addData([msg.payload], true);
}
});
})(scope);
</script>
Table 2:
<div id="screener2"></div>
<script>
var screener2Table = new Tabulator("#screener2", {
height:800,
//textSize : 10,
layout:"fitColumns",
columns:[
{title:"Number",field:"Number",hozAlign:"left",frozen:true},
{title:"Binance",field:"Binance",hozAlign:"center"},
//{title:"FTX Bots",field:"FTX Bots",hozAlign:"center"}, //Change this field to "FTX"
//{title:"FTX Trade",field:"FTX Trade",hozAlign:"center"}, //Or change this field
{title:"Gate",field:"Gate",hozAlign:"center"},
{title:"TOTAL",field:"TOTAL",hozAlign:"center"}
]
});
/*screener2Table.on("rowClick", function(e, row){
//Uncomment this whole event to use it
});*/
(function(scope){
scope.$watch('msg', function(msg){
if(msg){
screener2Table.setData(msg.payload, true);
}
});
})(scope);
</script>
I've gone through and changed some stuff in your table code to isolate the two tables and their functions/events. Each table now has its own name, namely screenerTable and screener2Table. This should make one respond to its own set of data and the other respond to its own. Now when you send data to a table, it should react.
The next thing I noticed is you're sending a key into the second table (FTX) that isn't being accounted for in the column definitions. I've commented out the column definitions that would pertain to it. Uncomment the one that applies and change the field value to "FTX" so it will pull that field.
Third, I've changed your addData on the second table to setData. Since you're passing the entire array every time and not adding to the table, setData() applies. Also, since you're passing in the array already, I took out the brackets that would have changed it into an array of arrays.
Lastly, I've commented out the whole rowClick event on the second table. If it's not being used yet, it doesn't need to be in the code. You can always uncomment it and add stuff to it or change it to a different type of listener. But as it stands, these two table setups should work, based off what I know is coming into them.
There will be some formatting that needs to be done as well as other stuff to make it pretty, but this should hopefully make your data display and add like it's supposed to. Let me know what you run up against.