nodejs ejs render array object in to table - javascript

Good day
I need to write a table from a database and i can't access the values, if the array is greater than 1...
If i do it like this:
//spielzeiten
var spielzeitenArr = [{
spzeit: "",
spielzeit_id: "",
}];
var spzeitData = await myDB.selectSpielzeit();
for (var i = 0; i < 1/*spzeitData.length*/; i++) {
spielzeitenArr[i].spzeit = "meine Zeit" /*spzeitData.spzeit*/;
spielzeitenArr[i].spielzeit_id = "meine ID"/*spzeitData.spielzeit_id*/;
}
res.render('index', {
firmen: firmanameArr,
block: blocknameArr,
datei: dateinameArr,
jinglein: jingleinArr,
jingleout: jingleoutArr,
szdata: spielzeitenArr
});
and on the ejs side it looks like this:
<table id="todoTable">
<tr>
<td class="tdList">Datum</td>
<td class="tdList">Zeit</td>
<td class="tdList">Start Jingle</td>
<td class="tdList">End Jingle</td>
<td class="tdList">Name</td>
<td class="tdList">
<div class="select-wrapper">
<select id="categoryFilter" class="selectCompany"></select>
</div>
</td>
<% szdata.forEach((item) => { %>
<tr></tr>
<td><%= item.spzeit %></td>
<td><%= item.spielzeit_id %></td>
<% }); %>
</table>
if i use my hardcoded value, it works. But if i try to change the i value to 2 or more, it gives me an error... why is this so?
Many thanks for the help!

You are initializing your spielzeiten array with a length of 1 and not increasing its size if you have more than one record. Thus, of course if you try to access an spielzeiten[i].spzeit with an index different from 0 you get an error.
You should probably initialize your array as an empty array and add new items during the loop.
spielzeiten = [];
for (let i = 0; i < spzeitData.length; i++) {
spielzeiten.push({
spzeit: spzeitData[i].spzeit,
id: spzeitData[i].spielzeit_id
});
}
You could also use the Array.map function to directly initialize your array
let spielzeiten = spzeitData.map(d => ({
spzeit: d.spzeit,
id: d.spielzeit_id
}));

Related

Can plotly use a dynamic html table as source data?

If I have an html table that contains values that are calculated based on filters within my file, can I get plotly to read and produce a plot based on those values?
I'm not sure that it matters to answering this question, but I use R primarily, and use the r code chunks calculate sums from a sharedData object names shared_ert that I created with the crosstalk package for R.
<table id="example" class="cell-border" style="width:100%">
<tr>
<th>Enrolled</th>
<th>Not Enrolled</th>
</tr>
<tr>
<td>
```{r, echo=FALSE, collapse=TRUE, warning=FALSE, message=FALSE}
summarywidget::summarywidget(shared_ert,statistic = 'sum',column = 'Enrolled')
```
</td>
<td>
```{r, echo=FALSE, collapse=TRUE, warning=FALSE, message=FALSE}
summarywidget::summarywidget(shared_ert,statistic = 'sum',column = 'Not Enrolled')
```
</td>
</tr>
</table>
Note that summary widget ends up producing a span tag within each td.
The spans look like <span id ="waffle" class="summarywidget html-widget html-widge-static-bound">1293</span>
So the table ends up looking like:
<table id="example" class="cell-border" style="width:100%">
<tr>
<th>Enrolled</th>
<th>Not Enrolled</th>
</tr>
<tr>
<td>
<span id ="waffle" class="summarywidget html-widget html-widge-static-bound">1293</span>
<script type="application/json" data-for="waffle">
### a bunch of data appears here, from which the 1293 value is derived
</script>
</td>
<td>
<span id ="iron" class="summarywidget html-widget html-widge-static-bound">948</span>
<script type="application/json" data-for="iron">
### a bunch of data appears here, from which the 948 value is derived
</script>
</td>
</tr>
</table>
From my limited understanding of the world of javascript, I need my data to look something like
var data = [
{
x: ['giraffes', 'orangutans', 'monkeys'],
y: [20, 14, 23],
type: 'bar'
}
];
So that I can get a plot produced with something like:
Plotly.newPlot('myDiv', data);
(directly from https://plotly.com/javascript/bar-charts/)
If I understand the problem correctly, I need to read the html table example and create a var that holds the table. After much searching around SO and the web in general, my guess is that the solution here: HTML Table to JSON pulls the table into the correct format. I'm trying
```{js}
function tableToJson(table) {
var data = [];
// first row needs to be headers
var headers = [];
for (var i=0; i<table.rows[0].cells.length; i++) {
headers[i] = table.rows[0].cells[i].innerHTML.toLowerCase().replace(/ /gi,'');
}
// go through cells
for (var i=1; i<table.rows.length; i++) {
var tableRow = table.rows[i];
var rowData = {};
for (var j=0; j<tableRow.cells.length; j++) {
rowData[ headers[j] ] = tableRow.cells[j].innerHTML;
}
data.push(rowData);
}
return data;
}
var tabdata = $document.getElementById('#example').tableToJSON();
```
I think from here, I need plotly to read the data from the table in it's current state, so I produce the plot using a button and onclick, as follows:
<button type="button" onclick="Plotly.newPlot('myDiv',tabdata);">Make Plot</button>
Upon clicking, the plotly plot appears, but doesn't have a data point anywhere.
I might be way off track in my methodology, so I defer to the original question: can I get plotly to read and produce a plot based on a dynamic html table?
Any help establishing a means to this end would be very much appreciated.
You need generate your json with keys x & y .So , here x value will be your header i.e : th tags and y values will be tdvalues . Now , if you have only one row in your table you can simply create JSON Object and then push value inside this using key i.e : data["x"] , data["y"]..etc .
Demo Code :
function tableToJSON(table) {
var data = {}; //create obj
data["x"] = [] //for x & y
data["y"] = []
data["type"] = "bar"
for (var i = 0; i < table.rows[0].cells.length; i++) {
data["x"].push(table.rows[0].cells[i].innerHTML.toLowerCase().trim()); //push x values
}
for (var i = 1; i < table.rows.length; i++) {
var tableRow = table.rows[i];
for (var j = 0; j < tableRow.cells.length; j++) {
data["y"].push(parseInt(tableRow.cells[j].querySelector(".summarywidget").textContent.trim()));
//push y values
console.log(tableRow.cells[j].querySelector(".summarywidget").textContent.trim())
}
}
return data;
}
function draw() {
var tabdata = tableToJSON(document.getElementById('example'));
tester = document.getElementById('tester');
Plotly.newPlot(tester, [tabdata])
}
<script src="https://cdn.plot.ly/plotly-2.1.0.min.js"></script>
<table id="example" class="cell-border" style="width:100%">
<tr>
<th>Enrolled</th>
<th>Not Enrolled</th>
</tr>
<tr>
<td>
<span id="waffle" class="summarywidget html-widget html-widge-static-bound">1293</span>
<script type="application/json" data-for="waffle">
###
a bunch of data appears here, from which the 1293 value is derived
</script>
</td>
<td>
<span id="iron" class="summarywidget html-widget html-widge-static-bound">948</span>
<script type="application/json" data-for="iron">
###
a bunch of data appears here, from which the 948 value is derived
</script>
</td>
</tr>
</table>
<button type="button" onclick="draw()">Make Plot</button>
<div id="tester" style="width:600px;height:250px;"></div>
Now , if you have mutliple rows in your table you need to generate JSON Array of that values .For that you need to keep main_array and then push values inside this main_array on each iterations.
Demo Code :
function tableToJSON(table) {
var main_array = [] //for main array
var for_x = [] //for x values
for (var i = 0; i < table.rows[0].cells.length; i++) {
for_x.push(table.rows[0].cells[i].innerHTML.toLowerCase().trim()); //push value
}
for (var i = 1; i < table.rows.length; i++) {
var tableRow = table.rows[i];
var data = {}; //create obj..
data["y"] = [] //for y values
for (var j = 0; j < tableRow.cells.length; j++) {
data["y"].push(parseInt(tableRow.cells[j].innerHTML.trim())); //push y values
}
//save other values..
data["x"] = for_x
data["type"] = "bar"
data["name"] = "Rows" + i
main_array.push(data) //push values in main array
}
//console..[{},{}..]
return main_array;
}
function draw() {
var tabdata = tableToJSON(document.getElementById('example'));
tester = document.getElementById('tester');
//pass it here
Plotly.newPlot(tester, tabdata, {
barmode: 'stack'
})
}
<script src="https://cdn.plot.ly/plotly-2.1.0.min.js"></script>
<table id="example" class="cell-border" style="width:100%">
<tr>
<th>Enrolled</th>
<th>Not Enrolled</th>
</tr>
<tr>
<td>
123
</td>
<td>
125
</td>
</tr>
<tr>
<td>
121
</td>
<td>
127
</td>
</tr>
</table>
<button type="button" onclick="draw()">Make Plot</button>
<div id="tester" style="width:600px;height:250px;"></div>

Ruby on Rails - javascript table filtering doesn't work

I have a strange problem. My filtering table doesn't work as it should. Here is javascript function that is activated the moment select value is changed.
function filterTable(opt, coln, tbId){
var filter = opt.value.toLowerCase(),
table = document.getElementById(tbId),
trs = table.getElementsByTagName("TR"),
col = table.querySelector('th[title='+coln+']').cellIndex,
x;
for (var i = 1; i < trs.length; i++){
x = trs[i].getElementsByTagName("TD")[col];
if(x){
classes = trs[i].classList;
classes.remove(coln+'-filtered-active');
classes.remove(coln+'-filtered-hidden');
if(filter){
console.log('tekst:' + x.textContent.length + ' ' + x.textContent +' || filter:' + filter);
if (x.textContent.toLowerCase() == filter) {
classes.add(coln+'-filtered-active');
}
else {
classes.add(coln+'-filtered-hidden');
}
}
trs[i].style.display = "";
for(var k=0; k < classes.length; k++){
if(classes[k].includes('filtered-hidden')) {
trs[i].style.display = "none";
break;
}
}
}
}
}
Here is rendered (I'm working in Rails) html structured containing one of the cells that belongs to the column I want to sort by.
<td>
<div class="cardLabel feature">feature</div>
</td>
The thing is x.textContent returns not only feature but also newlines and whitespaces that amounts to 55 characters. I believe that's why my filtering method doesn't work. But I have no idea how to solve this problem.This is the way how I get data to the view:
<tbody>
<% #cards.each do |card| %>
<tr>
<td>
<%= card[:card_name].truncate(50) %>
</td>
<td>
<div class="cardLabel <%= card[:label_name].gsub(/\s+/, "").downcase %>"><%=card[:label_name].upcase %></div>
</td>
<td><%= card[:time_from]+'-'+card[:time_to]+'h' %></td>
<td><%= card[:list_name] %></td>
<td><%= card[:organization_name] %></td>
<td><%= card[:board_name] %></td>
</tr>
<% end %>
</tbody>
Try innerText. From the code you posted innerText and textContent should be the same. But I assume you have other codes that add other elements that are not displayed but are picked up by textContent
https://jsfiddle.net/msyLm8u2/

How do I match two arrays in C# like in Javascript?

To make sure two arrays are the same in Javascript, this is what I do:
(inserting zeroes where there is missing data in item1)
var viewModel = #Html.Raw(Json.Encode(Model));
var items = viewModel.Date1;
var items2 = viewModel.Date2;
items = items2.map( row =>
//is there a matching row in items?
items.filter( r => r.theString == row.theString).length == 0 ?
//if not, fill with zeros
{theString:0, theCount:0} :
//if there is, return the items' row
items.filter( r => r.theString == row.theString)[0] );
I use that data for the barchart as percentages. I need to display the results in table form with the actual count numbers like this:
<div style="padding-top: 30px">
<table id="table_id" class="display">
<thead>
<tr>
<th>Month</th>
<th>Cancelled</th>
<th>Total</th>
</tr>
</thead>
<tbody>
#using (var e1 = Model.Date1.Reverse().GetEnumerator())
{
using (var e2 = Model.Date2.Reverse().GetEnumerator())
{
while (e1.MoveNext() && e2.MoveNext())
{
var item1 = e1.Current;
var item2 = e2.Current;
<tr>
<td>#item1.theDate.Value.ToString("MMMM-yyyy") </td>
<td>#item1.theCount</td>
<td>#item2.theCount</td>
</tr>
}
}
}
</tbody>
</table>
</div>
Problem is that those arrays haven't been fixed to match eachother, so the data it's displaying is incorrect. The dates (theDate) are not matching the values.
Or could I just use items and items2 from the javascript to make a table?
Something like this should work:
#foreach (var item1 in Model.Date1.Reverse())
{
var item2Count = Model.Date2.Where(i2 => i2.theDate == item1.theDate)
.Select(i2 => i2.theCount)
.FirstOrDefault();
<tr>
<td>#item1.theDate.Value.ToString("MMMM-yyyy") </td>
<td>#item1.theCount</td>
<td>#item2Count</td>
</tr>
}
This has the same n² asymptotic complexity as the JavaScript you posted, so if you had a very large number of items there's a chance you'd see slow performance. This could be resolved by creating a lookup of the Date2 values, like so:
#{
var item2CountsByDate = Model.Date2.ToLookup(i => i.theDate, i => i.theCount);
foreach (var item1 in Model.Date1.Reverse())
{
var item2Count = item2CountsByDate[item1.theDate]
.FirstOrDefault();
<tr>
<td>#item1.theDate.Value.ToString("MMMM-yyyy") </td>
<td>#item1.theCount</td>
<td>#item2Count</td>
</tr>
}
}

Accessing specific member of an ArrayList using Javascript

So, I have a table in a jsp page which shows the data fetched from a database via an ArrayList forwarded to the page. Each row of the table has a radio button corressponding to it. Now, I would like to access the elements in the row (the ArrayList's members on the selection of the corresponding radio button and then click of an 'edit' button)
Any thoughts as to how to achieve this would be very much appreciated. Here's my code for a bit intro.
<%
ArrayList<requestbean> reqjsp = new ArrayList<requestbean>();
reqjsp = (ArrayList<requestbean>) (request.getAttribute("reqdb"));
%>
<script type ="text/javascript">
function x() {
var ele = document.getElementsByName('reqradio');
var i = ele.length;
for ( var j = 0; j < i; j++ ) {
if ( ele[j].checked ) {
document.getElementById("edireq").disabled = false;
alert('request ' + ( j + 1 ) + ' selected');
//Here is where the functionality is desired to access reqjsp.get(j)
}
}
}
</script>
<input type="button" name="edireq" id="edireq" onclick="x()" value="Edit Request">
These are a few columns in my table.
<%
for ( int i = 0; i < reqjsp.size(); i++ ) {
%>
<tr>
<td> <input type="radio" name="reqradio" id="req<%=(i+1) %>"></td>
<td><%= reqjsp.get(i).getRequestid() %></td>
<td><%= reqjsp.get(i).getRequestor() %></td>
<td><%= reqjsp.get(i).getApprover() %></td>
</tr>
<%} %>
You could generate a JavaScript array with JSP code and then access this generated variable in your JavaScript. But you would not be able to change anything in the underlying Java object this way:
<script type ="text/javascript">
<%
ArrayList<requestbean> reqjsp = new ArrayList<requestbean>();
reqjsp = (ArrayList<requestbean>) (request.getAttribute("reqdb"));
%>
var myJsArray = new Array();
<%
for ( int i = 0; i < reqjsp.size(); i++ ) {
%>
myJsArray.push('<%= reqjsp.get(i) %>');
<%
}
%>
// JavaScript code to access the myJsArray array
</script>
The JSP code will generate this kind of code:
<script type ="text/javascript">
var myJsArray = new Array();
myJsArray.push('value1');
myJsArray.push('value2');
myJsArray.push('value3');
// JavaScript code to access the myJsArray array
</script>

Finding all checked check boxes isnt working

I've tried a few different ways of finding all the checkboxes that are checked but I don't know why this one isn't working.
JavaScript:
var idList = new Array();
function getIds()
{
var loopCounter = 0;
// find all the checked checkboxes
$('input[name^="check_"]:checked').each
{
function()
{
//fill the array with the values
idList[loopCounter] = $(this).val();
loopCounter += 1;
}
};
}
function showArray()
{
alert(idList);
}
and the HTML/ERB:
<% user_project_ids = #users_projects.collect { |up| up.project_id } %>
<fieldset style="width: 400px;">
<legend>Current Projects</legend>
<table>
<tr>
<th>Project ID</th>
<th>Project Name</th>
</tr>
<% #projects.each do |project| %>
<tr>
<td><%= project.id %></td>
<td><%= project.project_number %></td>
<td><%= project.project_name%></td>
<td><input name="check_<%= project.id %>" type="checkbox"
<%=' checked="yes"' if user_project_ids.include? project.id %>></td>
</tr>
<% end %>
</table>
</fieldset>
<div onclick="getIds();">
CLICK
</div>
<button onclick="showArray()">Click Again</button>
Not sure why this isn't working but maybe someone can see what I can't.
The parameter to .each need to be in round brackets .each()
function getIds()
{
var loopCounter = 0;
// find all the checked checkboxes
$('input[name^="check_"]:checked').each(function() {
//fill the array with the values
idList[loopCounter] = $(this).val();
loopCounter += 1;
});
}
The other answer already told you about your problem, but your code can be improved. There is no need to use a loop counter, each provides the iteration number.
function getIds()
{
//reset idArray
idList = [];
// find all the checked checkboxes
$('input[name^="check_"]:checked').each(function( ind ) {
idList[ind] = $(this).val();
});
}
You do not even need the index when you have methods on the array to add element
function getIds()
{
//reset idArray
idList = [];
// find all the checked checkboxes
$('input[name^="check_"]:checked').each(function() {
idList.push( $(this).val() );
});
}

Categories

Resources