Generated 2 tables based on 2 separate javascript arrays - javascript

I am trying to build out 2 html tables from 2 different JavaScript data arrays.
The first table builds out fine and structure looks great but the second table doesn't populate data.
I tried adjusting the naming but I think since it's looking for "tbody" both times.
Is there another variable to adjust this or perhaps a better way to have 2 separate tables from 2 different data arrays?
I swapped the naming and added ID tags to the tbody with no change in results. I was going to just rename the data tables but seems like the construction of the second table grabbing tbody is just adjusting the first tbody.
<div style="float: left;margin-right:10px">
<table>
<thead>
<tr align="center">
<th><h3>Name</h3></th>
<th><h3>Time</h3></th>
<th><h3>Temp</h3></th>
<th><h3>Peel</h3></th>
</tr>
</thead>
<tbody id="tbody"></tbody>
</table>
</div>
<script>
const data = [
{name: "Apple", time: "25sec", temp: "100F", peel: "Peeler"},
{name: "Orange", time: "50sec", temp: "200F", peel: "Knife"},
]
const table = document.querySelector('tbody')
data.forEach((item) => {
table.insertAdjacentHTML( 'beforeend', `<tr>
<td>${item.name}</td>
<td>${item.time}</td>
<td>${item.temp} </td>
<td>${item.peel}</td>
</tr>`)
})
</script>
<div style="float: left">
<table>
<thead>
<tr align="center">
<th><h3>Name</h3></th>
<th><h3>Time</h3></th>
<th><h3>Temp</h3></th>
<th><h3>Peel</h3></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<script>
<script>
const data = [
{name: "Apple", time: "25sec", temp: "100F", peel: "Peeler"},
{name: "Orange", time: "50sec", temp: "200F", peel: "Knife"},
]
const table = document.querySelector('tbody')
data.forEach((item) => {
table.insertAdjacentHTML( 'beforeend', `<tr>
<td>${item.name}</td>
<td>${item.time}</td>
<td>${item.temp}</td>
<td>${item.peel}</td>
</tr>`)
})
</script>

Consider extracting the row creation into a function and giving the two tbody elements unique ids to distinguish them.
function addRows(tbody, data) {
data.forEach((item) => {
tbody.insertAdjacentHTML('beforeend', `<tr>
<td>${item.name}</td>
<td>${item.time}</td>
<td>${item.temp} </td>
<td>${item.peel}</td>
</tr>`)
});
}
const data1=[{name:"Apple",time:"25sec",temp:"100F",peel:"Peeler"},{name:"Orange",time:"50sec",temp:"200F",peel:"Knife"},];
const tbody1 = document.querySelector('#tbody1');
addRows(tbody1, data1);
const data2=[{name:"Apple",time:"25sec",temp:"100F",peel:"Peeler"},{name:"Orange",time:"50sec",temp:"200F",peel:"Knife"},];
const tbody2 = document.querySelector('#tbody2');
addRows(tbody2, data2);
<div style="float: left;margin-right:10px">
<table>
<thead>
<tr align="center">
<th><h3>Name</h3></th>
<th><h3>Time</h3></th>
<th><h3>Temp</h3></th>
<th><h3>Peel</h3></th>
</tr>
</thead>
<tbody id="tbody1"></tbody>
</table>
</div>
<div style="float: left">
<table>
<thead>
<tr align="center">
<th><h3>Name</h3></th>
<th><h3>Time</h3></th>
<th><h3>Temp</h3></th>
<th><h3>Peel</h3></th>
</tr>
</thead>
<tbody id="tbody2"></tbody>
</table>
</div>

There are a few issues with your code.
You are declaring data and table as constants in the first <script> tag, and then you try to reassing their values in the second <script> tag. (constant variables cannot be reassigned).
In addition, document.querySelector('tbody') will always select the very first <tbody> element that is found on the page. This would cause to select the same table twice.
<div style="float: left;margin-right:10px">
<table>
<thead>
<tr align="center">
<th><h3>Name</h3></th>
<th><h3>Time</h3></th>
<th><h3>Temp</h3></th>
<th><h3>Peel</h3></th>
</tr>
</thead>
<tbody id="table-1"></tbody>
</table>
</div>
<div style="float: left">
<table>
<thead>
<tr align="center">
<th><h3>Name</h3></th>
<th><h3>Time</h3></th>
<th><h3>Temp</h3></th>
<th><h3>Peel</h3></th>
</tr>
</thead>
<tbody id="table-2"></tbody>
</table>
</div>
<script>
// Array containing data
let data = [
{name: "Apple", time: "25sec", temp: "100F", peel: "Peeler"},
{name: "Orange", time: "50sec", temp: "200F", peel: "Knife"},
];
// The tbodies have different IDs
let table_1 = document.querySelector('#table-1');
let table_2 = document.querySelector('#table-2');
// Object [] notation
table_1.insertAdjacentHTML( 'beforeend',
`
<tr>
<td>${data[0]['name']}</td>
<td>${data[0]['time']}</td>
<td>${data[0]['temp']}</td>
<td>${data[0]['peel']}</td>
</tr>
`
);
table_2.insertAdjacentHTML( 'beforeend',
`
<tr>
<td>${data[1]['name']}</td>
<td>${data[1]['time']}</td>
<td>${data[1]['temp']}</td>
<td>${data[1]['peel']}</td>
</tr>
`
);
</script>
This is how I would refactor this code, but there are endless ways to solve this.

You can't give to a tbody element a id like "tbody" and left the other without id.
By doing this you are selecting twice the same tbody tag (the first), regardless of their IDs.
So use two different id like "tb1" and "tb2".
For the remnant things you can refer to #Unmitigated answer that beat me in time and is the best. ^_^

Related

jQuery appendTo ignoring last element

I'm trying to append a copy of an element to the bottom of the parent element. It seems to append everything above the last element within the parent. Live example on JSFiddle
var count = 1;
$("#addBtn").click(function(){
$('#trid1').clone().appendTo('table#exampleTable > tbody');
count++;
$('#trid1').last().prop('id', 'trid'+count);
$('#trid'+count+' > th').html(count);
});
<!-- jQuery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table" id="exampleTable">
<thead>
<tr>
<th scope="col">c1</th>
</tr>
</thead>
<tbody>
<tr id="trid1" class="trclass">
<th scope="row">1</th>
</tr>
</tbody>
</table>
<button type="button" id="addBtn">Add</button>
I would change the id before appending the new element to the DOM.
Anyway I slightly refactored your code with that strategy in mind and better dealt with the current index every time you click the add button. The latest index gets saved in a data attribute in the table.
$("#addBtn").click(function(){
const latestIndex = $('#exampleTable').data('latest-index');
let i = latestIndex+1;
const newRow = $('#trid1').clone();
newRow.prop('id', `trid${i}`);
newRow.data('index', i);
newRow.text(i);
newRow.appendTo('table#exampleTable > tbody');
$('#exampleTable').data('latest-index', i);
});
button{
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table" id="exampleTable" data-latest-index="1">
<thead>
<tr>
<th scope="col">Rows</th>
</tr>
</thead>
<tbody>
<tr id="trid1" class="trclass">
<th scope="row">1</th>
</tr>
</tbody>
</table>
<button type="button" id="addBtn">Add</button>

How can I re-render a view after deleting an object from an array, in Svelte?

I am working on a small Svelte application, for learning purposes (Im new to Svelte). The application uses an array of objects displayed in a view as an HTML table:
let countries = [
{ code: "AF", name: "Afghanistan" },
{ code: "AL", name: "Albania" },
{ code: "IL", name: "Israel" }
];
<table class="table table-bordered">
<thead>
<tr>
<th>#</th>
<th>Code</th>
<th>Name</th>
<th class="text-right">Actions</th>
</tr>
</thead>
<tbody>
{#if countries.length}
{#each countries as c, index}
<tr>
<td>{index+1}</td>
<td>{c.code}</td>
<td>{c.name}</td>
<td class="text-right">
<button data-code="{c.code}" on:click="{deleteCountry}" class="btn btn-sm btn-danger">Delete</button>
</td>
</tr>
{/each}
{:else}
<tr>
<td colspan="4">There are no countries</td>
</tr>
{/if}
</tbody>
</table>
I am doing a delete operation this way:
function deleteCountry(){
let ccode = this.getAttribute('data-code');
let itemIdx = countries.findIndex(x => x.code == ccode);
countries.splice(itemIdx,1);
console.log(countries);
}
There is a REPL here.
The problem
I have been unable to render the table (view) again, after the countries array is updated (an element is deleted from it).
How do I do that?
add
countries = countries;
after this line
countries.splice(itemIdx,1);
since reactivity/rerendering/UI update only marked after assignment.
For svelte to pick up the change to your array of countries, you need to create a new reference of the array. For this you could use the Array.filter method.
<script>
let countries = [
{ code: "AF", name: "Afghanistan" },
{ code: "AL", name: "Albania" },
{ code: "IL", name: "Israel" }
];
function deleteCountry(code) {
countries = countries.filter(c => c.code !== code)
}
</script>
<table class="table table-bordered">
<thead>
<tr>
<th>#</th>
<th>Code</th>
<th>Name</th>
<th class="text-right">Actions</th>
</tr>
</thead>
<tbody>
{#if countries.length}
{#each countries as c, index}
<tr>
<td>{index+1}</td>
<td>{c.code}</td>
<td>{c.name}</td>
<td class="text-right">
<button on:click="{() => deleteCountry(c.code)}" class="btn btn-sm btn-danger">Delete</button>
</td>
</tr>
{/each}
{:else}
<tr>
<td colspan="4">There are no countries</td>
</tr>
{/if}
</tbody>
</table>
Also you can directly use the country code as an argument for the deleteCountry method.

Save whole table html code in a variable

I have a table where the cell content is editable.
Now I want, after I finished editing the table, the html code from the table with all values.
Here is a table:
<table class="table table-bordered content">
<thead>
<tr>
<th>bla</th>
<th>bla bla</th>
<th>bla bla bla </th>
<th>more bla</th>
</tr>
</thead>
<tbody>
<tr contenteditable="true">
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr contenteditable="true">
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<button id="save">Save</button>
That's my JS code:
$('#save').on('click', function () {
var table = $('.content').html();
alert(table);
});
The problem is that if I console.log the table variable I get this output:
<thead>
<tr>
<th>bla</th>
<th>bla bla</th>
<th>bla bla bla </th>
<th>more bla</th>
</tr>
</thead>
<tbody>
<tr contenteditable="true">
<td>dwad</td>
<td>dwada</td>
<td>dawdaw</td>
<td>dawdaw</td>
</tr>
<tr contenteditable="true">
<td>daw<br></td>
<td>daw<br></td>
<td>dwadaw<br></td>
<td>daw<br></td>
</tr>
</tbody>
If you have a closer look you can see that the
<table class=" ... "> and the </table> tag are gone but I also need them.
Does someone know what I can do to also get the table-tags ?
Try this:
var table = $('.content')[0].outerHTML;
alert(table);
Should work in every browser
Use outerHTML on the node element. Like this:
$('#save').on('click', function () {
var table = $('.content')[0].outerHTML;
alert(table);
});
Use outerHTML
$('.content').get(0).outerHTML
Check the example on JSfidle
$('#save').on('click', function () {
var table = $('.content')[0].html();
alert(table);
});
This should work.
Use Element.outerHTML
The outerHTML attribute of the element DOM interface gets the serialized HTML fragment describing the element including its descendants. It can be set to replace the element with nodes parsed from the given string.
$('#save').on('click', function () {
var table = $('.content');
alert(table.get(0).outerHTML);
});

Appending a table row from body tag to another table after updating elements within the row

I was told it is good practice to never use HTML tags in JavaScript. So I'm trying my very best to execute the following, but I'm not getting what I want.
I have 2 tables:
Table #1: a table I use to append rows to.
Table #2: a hidden table that has only 1 row, I use that row to change its content and append it to Table #1
Table #1
<table id="myTable">
<thead>
<tr>
<th>Full Name</th>
<th>ID</th>
<th>Email</th>
<th>Phone Number</th>
<th>Job Title</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
Table #2
<table id='hiddenTable'>
<tbody>
<tr>
<td><span id="fname"></span></td>
<td><span id="id"></span></td>
<td><span id="email"></span></td>
<td><span id="pnumber"></span></td>
<td><span id="job"></span></td>
</tr>
</tbody>
</table>
Append Function
function addRow(data){
$('#fname').text(data.fname);
$('#id').text(data.id);
$('#email').text(data.email);
$('#pnumber').text(data.pnumber);
$('#job').text(data.job);
var row = $('#hiddenTable').children('tbody').children('tr:first').clone();
$('#myTable > tbody:last-child').append(row);
}
All the snaps are updated everytime addRow() is executed, but when retrieving the row element from the hidden table, it remains empty, unchanged.
please explain why is this happening? and help me make this work without using html tags in javascript and without using the insert row function.
As suggested by #CBroe; the main issue is duplicate ids getting assigned to DOM element. To overcome that first change hidden table's HTML a bit to have class instead of id. Please have a look at below snippet:
function addRow(data) {
//first clone the row from hidden table
var row = $('#hiddenTable').children('tbody').children('tr:first').clone();
//find the span having unique class assigned to them and then set the value
row.find('.fname').text(data.fname);
row.find('.id').text(data.id);
row.find('.email').text(data.email);
row.find('.pnumber').text(data.pnumber);
row.find('.job').text(data.job);
//append the newly formed row to main table
$('#myTable tbody').append(row);
}
$(function() {
var data1 = {
fname: "some name",
id: "some id",
email: "some#email.com",
pnumber: "1212121212",
job: "some job"
};
addRow(data1);
var data2 = {
fname: "some name 22",
id: "some id 22",
email: "some22#email.com",
pnumber: "88888888888888",
job: "some job 22"
};
addRow(data2);
});
#hiddenTable {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<table id="myTable">
<thead>
<tr>
<th>Full Name</th>
<th>ID</th>
<th>Email</th>
<th>Phone Number</th>
<th>Job Title</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<table id='hiddenTable'>
<tbody>
<tr>
<td><span class="fname">aaaaaa</span>
</td>
<td><span class="id"></span>
</td>
<td><span class="email"></span>
</td>
<td><span class="pnumber"></span>
</td>
<td><span class="job"></span>
</td>
</tr>
</tbody>
</table>
All you have done is correct and should work as you expected unless your data object's incorrect. Make a console of your data object and try to figure out how you can extract property from that.
function addRow(data) {
$('#fname').text(data.fname);
$('#id').text(data.id);
$('#email').text(data.email);
$('#pnumber').text(data.pnumber);
$('#job').text(data.job);
var row = $('#hiddenTable tr').first().clone();
$('#myTable tbody').append(row);
}
var data = {
fname: 'first name',
id: '12121',
email: 'email#gmail.com',
pnumber: '111111111',
job: 'my job'
}
addRow(data);
#hiddenTable {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="myTable">
<thead>
<tr>
<th>Full Name</th>
<th>ID</th>
<th>Email</th>
<th>Phone Number</th>
<th>Job Title</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<table id='hiddenTable'>
<tbody>
<tr>
<td><span id="fname"></span>
</td>
<td><span id="id"></span>
</td>
<td><span id="email"></span>
</td>
<td><span id="pnumber"></span>
</td>
<td><span id="job"></span>
</td>
</tr>
</tbody>
</table>
Try this JSFiddle solution.
I change something on addRow function:
function addRow(data){
$('#hiddenTable #fname').text(data.fname);
$('#hiddenTable #id').text(data.id);
$('#hiddenTable #email').text(data.email);
$('#hiddenTable #pnumber').text(data.pnumber);
$('#hiddenTable #job').text(data.job);
var row = $('#hiddenTable tbody').html();
$('#myTable > tbody').append(row);
}

Merging javascript objects into HTML table

I have two javascript objects, the contents of which came from these two HTML tables.
Each pre-merge table now has it's own object. The object is structured as follows:
The first array element within the object contains the column headers from the pre-merge tables, and the array elements following that contain the <tr> data from each table.
Is it possible to merge these two objects together to produce one HTML table? As you can see the in the pre-merge tables the x-value is shared between both, meaning it is common between the two objects too. I thought there may be a way of comparing these values, and then populating the table, but I'm not sure how.
I would like the merged table to look like the following:
x-value: common dates shared between objects
columns: data from each of the pre-merge tables with their headers
Here is my code (you can also see it on this CodePenHere):
$(document).ready(function(){
gatherData();
results();
});
function gatherData(){
data = [];
tables = $('.before').find('table');
$(tables).each(function(index){
table = [];
var headers = $(this).find('tr:first');
var headerText = [];
headerText.push($(headers).find('td:nth-child(1)').text());
headerText.push($(headers).find('td:nth-child(2)').text());
table.push(headerText)
$(this).find('tr').each(function(index){
var rowContent = [];
if (index != 0){
$(this).find('td').each(function(index){
rowContent.push($(this).text());
})
}
table.push(rowContent)
})
data.push({table: table})
});
console.log(data)
}
function results(){
var results = $('.after1').find('thead');
$(results).append("<th>" + data[0].table[0][0] + "</th>");
for (i in data){
$(results).append("<th>" + data[i].table[0][1] + "</th>");
var b = data[i].table.length;
for (a = 2; a < b; a++){
console.log(data[i].table[a][0] + " || " + data[i].table[a][1])
}
}
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<div class="container">
<h1 class="page-header">Formatter.js</h1>
</div>
<div class="container before">
<h3>Before</h3>
<table border=1 cellspacing=0 cellpadding=0 alignment="" class="a" id="3">
<tbody>
<tr>
<td>x-value</td>
<td>Operational Planned</td>
</tr>
<tr>
<td>09/11/2015</td>
<td>0</td>
</tr>
<tr>
<td>10/11/2015</td>
<td>0</td>
</tr>
<tr>
<td>11/11/2015</td>
<td>66358</td>
</tr>
<tr>
<td>12/11/2015</td>
<td>65990</td>
</tr>
<tr>
<td>13/11/2015</td>
<td>55993</td>
</tr>
<tr>
<td>14/11/2015</td>
<td>0</td>
</tr>
<tr>
<td>15/11/2015</td>
<td>0</td>
</tr>
</tbody>
</table>
<table border=1 cellspacing=0 cellpadding=0 alignment="" class="a" id="3">
<tbody>
<tr>
<td>x-value</td>
<td>Something Else</td>
</tr>
<tr>
<td>09/11/2015</td>
<td>0</td>
</tr>
<tr>
<td>10/11/2015</td>
<td>0</td>
</tr>
<tr>
<td>11/11/2015</td>
<td>2552</td>
</tr>
<tr>
<td>12/11/2015</td>
<td>86234</td>
</tr>
<tr>
<td>13/11/2015</td>
<td>33623</td>
</tr>
<tr>
<td>14/11/2015</td>
<td>0</td>
</tr>
<tr>
<td>15/11/2015</td>
<td>0</td>
</tr>
</tbody>
</table>
<hr>
</div>
<div class="container after">
<h3>After</h3>
<table class="table after1">
<thead>
</thead>
<tbody>
</tbody>
</table>
</div>
As I understand your issue, you want to merge the tables by the key values in coloumn x-value.
Here is how I would do it:
Collect data from each table into a dictionary with coloumn x-value as key
Save values for each key as array.
The main part is collecting the data in the dictionary. Here is the part:
var table = {
header: [],
data: {}
};
$(this).find('tr').each(function(index) {
// ignore first row
if (index === 0) return true;
// read all data for row
var rowData = [];
$(this).find('td').each(function() {
var value = $(this).text();
rowData.push(value);
});
// key value for dictionery
var key = rowData[0];
// add value to array in dictionary if existing or create array
if(table.data[key]) {
table.data[key].push(rowData[1]);
} else {
table.data[key] = [rowData[1]];
}
});
By using a simple javascript object as a dictionary we create properties on the fly, just like a dictionary.
See the plunker for the full script. I've written comments on the different parts to make the functionality clear. Let me know if anything is unclear.
As a note on your code. You can use multiple arguments in the jQuery selector to make your selections simpler, so this (see note below)
tables = $('.before').find('table');
can become this:
tables = $('.before table');
Edit
As noted by Mark Schultheiss in the comments, the later, but shorter syntax for jQuery selectors can be slower than the first one on large DOMs. So use the extended syntax on large DOMs. I've updated the plunker to use the better performing syntax.

Categories

Resources