Creating HTML from local storage data - javascript

I want to take data from my local storage and show it dynamically. In this table below is the code that I tried but it is not working.
<script>
var cart= JSON.parse( localStorage.getItem('Mylinklist'));
$.each(Mylinklist, function(key, value){
$('tbody').append(`<tr>
<td>${cart.name}</td>
<td>${cart.url}</td>
</tr>`)
})
</script>
<div id="actionerpanel" class="col col-lg-6 col-12 ">
<div class="rapi-card m-lg-5 m-1">
<b class="rapi-card-colored-header p-3 mb-2">Quick Links <span>+</span></b>
<div class="container">
<div class="row justify-content-center "><table class="table">
<thead>
<tr>
<th scope="col">Link Name</th>
<th scope="col">Url</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>

You can use insertAdjacentHTML and literals templates for this kind of operation.
var carts = [{
id: 'id1',
name: 'test',
url: 'url'
}, {
id: 'id2',
name: 'test2',
url: 'url2'
}] //Fake localstorage replace it with JSON.parse
carts.forEach(cart => {
let button = `<button onclick="alert('Item id : ${cart.id}')">Click</button>`,
row = `<tr id="item_${cart.id}"><td>${cart.name}</td><td>${cart.url}</td><td>${button}</td></tr>`;
document.querySelector('tbody').insertAdjacentHTML('beforeend', row)
})
//OR
for (let cart of carts) {
let button = `<button onclick="alert('Item id : ${cart.id}')">Click</button>`,
row = `<tr id="item_${cart.id}"><td>${cart.name}</td><td>${cart.url}</td><td>${button}</td></tr>`;
document.querySelector('tbody').insertAdjacentHTML('beforeend', row)
}
<table class="table">
<thead>
<tr>
<th scope="col">Link Name</th>
<th scope="col">Url</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody></tbody>
</table>

You can make it with plain JS like this. I had to comment out the places with localstorage. Because access to localStorage is not allowed on SO. As soon as you add them, it works.
const arr = [
{id: 123, name: "google", url: "https://www.google.com"},
{id: 124, name: "bing", url: "https://www.bing.com"},
]
// store to localStorage
// localStorage.setItem('Mylinklist', JSON.stringify(arr));
// get from localStorage
// const data = JSON.parse(localStorage.getItem('Mylinklist'));
const table = document.querySelector('.table');
// change obj.forEach to data.forEach because in SO you cant use localStorage!!!
arr.forEach((e) => {
let tr = document.createElement('TR');
let td_name = document.createElement('TD');
let td_url = document.createElement('TD');
td_name.innerHTML = e.name
td_url.innerHTML = e.url
tr.append(td_name)
tr.append(td_url)
table.append(tr)
})
<div class="row justify-content-center "><table class="table">
<thead>
<tr>
<th scope="col">Link Name</th>
<th scope="col">Url</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>

Related

Generated 2 tables based on 2 separate javascript arrays

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. ^_^

How to make first column's every row clickable to get data from that whole row? JavaScript

I'm trying to make a table's first column's each row (in this case order IDs) clickable so that I can display more info from this specific order ID in another container on my website. I looped through some JSON data to create the table like this:
function printData(jsonData) {
let myTable = document.getElementById("jsonTable")
for(let i=0; i < jsonData.length; i++) {
let row = `<tr>
<td>${jsonData[i].orderid}</td>
<td>${jsonData[i].customerid}</td>
<td>${jsonData[i].customer}</td>
<td>${jsonData[i].invaddr}</td>
<td>${jsonData[i].delivaddr}</td>
<td>${jsonData[i].deliverydate}</td>
<td>${jsonData[i].respsalesperson}</td></tr>`
jsonTable.innerHTML += row
}
}
And this is how my HTML file looks like:
<div class="datatable">
<div class="datatablecontent">
<table class="jsontable">
<tr id="jsontr">
<th>Order ID</th>
<th>Customer ID</th>
<th>Customer</th>
<th>InvAddr</th>
<th>Delivery Address</th>
<th>Delivery Date</th>
<th>Resp. For Sale </th>
<tbody id="jsonTable">
</tbody>
</tr>
</table>
</div>
</div>
While iterating over jsonData, you can declare a callback in an event listener.
Because you're using template literals, I'm keeping it concise and passing the row index. You can also pass the data itself by adding an event listener in JS, to do that you'll need to access the element.
function logRowData(index) {
console.log(jsonData[index])
}
let jsonData = [
{orderid: 0, customerid:14, customer: 'abc'},
{orderid: 1, customerid:25, customer: 'xyz'}
]
printData(jsonData)
function printData(jsonData) {
let myTable = document.getElementById("jsonTable")
for(let i=0; i < jsonData.length; i++) {
let row = `<tr>
<td onclick={logRowData(${i})}>${jsonData[i].orderid}</td>
<td>${jsonData[i].customerid}</td>
<td>${jsonData[i].customer}</td></tr>`
jsonTable.innerHTML += row
}
}
<div class="datatable">
<div class="datatablecontent">
<table class="jsontable">
<tr id="jsontr">
<th>Order ID</th>
<th>Customer ID</th>
<th>Customer</th>
<tbody id="jsonTable">
</tbody>
</tr>
</table>
</div>
</div>

Fetched data duplicates itself after sorting

I fetched data by using fetch api into a table. I sort my data by clicking on column headers. It works but after it's sorted,it duplicates data. I checked on it,but i guess there's someting i've missed.
let data =[];
function veriAl()
{
fetch('https://jsonplaceholder.typicode.com/users')
.then(response =>{
if(!response.ok)
{
throw Error("ERROR");
}
return response.json();
})
.then(veri => {
data=veri;
veriEkle(data);
}).catch(error => {
console.log(error);
});
}
const sort_data = (field) =>
{
data.sort((a,b) => {
let valueA=a[field];
let valueB= b[field];
if(valueA<valueB)
{
return -1;
}
else if(valueB>valueA)
{
return 1;
}
return 0;
})
console.log("sıralandı"+field+"e göre",data);
veriEkle(data);
}
const veriEkle =(array)=>
{
const html=array.map(user =>{
return `<table class="user">
<td> ${user.id}</td>
<td>${user.name}</td>
<td>${user.username}</td>
<td>${user.email}</td>
<td>${user.address.street}/${user.address.suite}/${user.address.city}</td>
</table>
`;
}).join("");
console.log(html); document.querySelector('#veri_tablo').insertAdjacentHTML("afterbegin",html);
}
veriAl();
<div class="container">
<div class="row justify-content-center">
<table class="table" id="veri_tablo">
<thead class="thead-dark">
<tr>
<th onclick="sort_data('id')">ID</th>
<th onclick="sort_data('name')">Name</th>
<th onclick="sort_data('username')">Username</th>
<th onclick="sort_data('email')">Email</th>
<th onclick="sort_data('address')">Adres</th>
</tr>
</thead>
</table>
<div>
</div>
console.log("sıralandı"+field+"e göre",data);
veriEkle(data); //---->Here
You should maybe edit here like veriEkle(...data); or you should use filter function instead of "sort"
There seems to be nothing wrong with your data. It's not being duplicated. It is the html that's being duplicated. You're appending html without removing the existing entries. You should have a container element and change the inner html of that container instead.
Your js should look something like this...
//...
const veriEkle = (array) => {
const html = array.map(user => {
return `<tr class="user">
<td> ${user.id}</td>
<td>${user.name}</td>
<td>${user.username}</td>
<td>${user.email}</td><td>${user.address.street}/${user.address.suite}/${user.address.city}</td>
</tr>
`;
}).join("");
console.log(html);
document.getElementById('table_content').innerHTML = html;
}
And your html
<div class="container">
<div class="row justify-content-center">
<table class="table" id="veri_tablo">
<thead class="thead-dark">
<tr>
<th onclick="sort_data('id')">
ID
</th>
<th onclick="sort_data('name')">
Name
</th>
<th onclick="sort_data('username')">
Username
</th>
<th onclick="sort_data('email')">
Email
</th>
<th onclick="sort_data('address')">
Adress
</th>
</tr>
<tbody id="table_content" /> //the container element
</thead>
</table>
<div />
</div>
</div>
PS Using the innerHTML property is not considered best practice and you should look at this link for the best ways to create and render elements from html strings.

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.

How can I duplicate this in jQuery?

I have this code:
/* Modify the footer row to match what we want */
var nCells = nRow.getElementsByTagName('th');
nCells[1].innerHTML = iPageCPSV;
nCells[2].innerHTML = iPageCGV;
nCells[3].innerHTML = iPagePPSV;
nCells[4].innerHTML = iPagePGV;
It works just fine as it is. However I have added another <tr> into the section now. And I am having trouble figureing out how to populate the <th> in the second <tr>
<tfoot>
<tr style="background-color: #DDDDDD;">
<th align="right" colspan="6">
Page Total:
</th>
<th align="left"></th>
<th align="left"></th>
<th align="left"></th>
<th align="left"></th>
</tr>
<tr style="background-color: #DDDDDD;">
<th align="right" colspan="6">
Downline Total:
</th>
<th align="left"></th>
<th align="left"></th>
<th align="left"></th>
<th align="left"></th>
</tr>
</tfoot>
Before I added the second <tr> with more <th> everything worked. It still works, I just don't know how to populate the data into the second row. Can anyone help me modify the existing JavaScript or tell me how to duplicate it into jQuery?
Without jQuery...
var foot = nRow.getElementsByTagName('tfoot')[0];
foot.rows[0].cells[1].innerHTML = iPageCPSV;
foot.rows[0].cells[2].innerHTML = iPageCGV;
foot.rows[0].cells[3].innerHTML = iPagePPSV;
foot.rows[0].cells[4].innerHTML = iPagePGV;
foot.rows[1].cells[1].innerHTML = iPageCPSV;
foot.rows[1].cells[2].innerHTML = iPageCGV;
foot.rows[1].cells[3].innerHTML = iPagePPSV;
foot.rows[1].cells[4].innerHTML = iPagePGV;
Or with...
var foot = $('tfoot').first();
foot.children().each(function(i, row) {
row.cells[1].innerHTML = iPageCPSV;
row.cells[2].innerHTML = iPageCGV;
row.cells[3].innerHTML = iPagePPSV;
row.cells[4].innerHTML = iPagePGV;
});
A more modern solution...
var rows = nRow.getElementsByTagName('tfoot')[0].rows,
data = [iPageCPSV, iPageCGV, iPagePPSV, iPagePGV];
[].forEach.call(rows, function(el, i) {
data.forEach(function(item, ii) {
el.cells[ii + 1].innerHTML = item;
});
});
Since you need different data for each cell, I'd suggest putting it all in an Array, getting a collection of all the elements, and pairing the two...
var data = [iPageCPSV, iPageCGV, iPagePPSV, iPagePGV, 'foo', 'bar', 'baz', 'buz'];
$('tfoot > tr > th:not(:first-child)').html(function(i, el) {
return data[i];
});

Categories

Resources