I'm having this issues with the below table in which I want to set the 'view book' link and reserved to be the last in the row, but apparently the x = TABLE_ROW.insertCell(-1) is not working.
I just want to have the link/span at the end of the table row. Shouldn't the -1 argument be enough for this?
Can you please help me identifying what I'm doing wrong?
var data = {
"headings": {
"propBook": "Book",
"propAuthor": "Author",
"propYear": "Year",
},
"items": [{
"fields": {
"propBook": "The Great Gatsby",
"propAuthor": "F Scott Fitzgerald",
"propYear": "1925",
},
"button": {
"name": "View book",
"propURL": "https://google.com"
}
},
{
"fields": {
"propBook": "The Grapes of Wrath",
"propAuthor": "John Steinbeck",
"propYear": "1939",
},
"button": {
"name": "View book",
"propURL": ""
}
},
{
"fields": {
"propBook": "A Wild Sheep Chase",
"propAuthor": "Haruki Murakami",
"propYear": "1982",
},
"button": {
"name": "View book",
"propURL": "https://google.com"
}
}
]
}
const HEADINGS = data.headings;
const ITEMS = data.items;
const TABLE_WRAPPER = document.querySelector('.book-component .table-wrapper');
const TABLE = document.createElement('table');
TABLE.setAttribute('class', 'pagination');
TABLE_WRAPPER.appendChild(TABLE);
for (const field in data) {
const TABLE_ROW = document.createElement('tr');
TABLE_ROW.setAttribute('id', 'myRow');
if (field == 'headings') {
for (const child in HEADINGS) {
const HEADER_CELL = document.createElement('th');
TABLE_ROW.appendChild(HEADER_CELL);
HEADER_CELL.setAttribute('class', 'sort-cta');
HEADER_CELL.innerText = HEADINGS[child];
TABLE.appendChild(TABLE_ROW);
}
} else if (field == 'items') {
for (const child in ITEMS) {
const TABLE_ROW = document.createElement('tr');
let item = ITEMS[child].fields;
let btn = ITEMS[child].button;
if (btn.propURL !== '') {
let link = document.createElement('a');
link.setAttribute('href', btn.propURL);
link.innerHTML = btn.name;
x = TABLE_ROW.insertCell(-1);
x.appendChild(link);
} else {
let link = document.createElement('span');
link.innerHTML = 'Reserved';
x = TABLE_ROW.insertCell(-1);
x.appendChild(link);
}
for (const row in item) {
const TABLE_DATA = document.createElement('td');
TABLE_ROW.appendChild(TABLE_DATA);
TABLE_DATA.innerText = item[row];
TABLE.appendChild(TABLE_ROW);
}
}
}
}
tr.inactive {
display: none;
}
.table-wrapper {
display: flex;
flex-direction: column-reverse;
}
.pager {
display: flex;
justify-content: center;
padding: 0;
margin-top: 10px;
font-weight: 800;
}
.pager-item.selected {
outline: none;
border-color: #0077cc;
background: #0077cc;
color: #fff;
cursor: default;
}
<div class="book-component">
<div class="table-wrapper">
</div>
</div>
You just should inset cell data first. Then insert the link cell at the end of a table row.
http://jsfiddle.net/u1bvq376/
Here is a sample. Hope to help, my friend :))
for (const field in data) {
const TABLE_ROW = document.createElement('tr');
TABLE_ROW.setAttribute('id', 'myRow');
if (field == 'headings') {
for (const child in HEADINGS) {
const HEADER_CELL = document.createElement('th');
TABLE_ROW.appendChild(HEADER_CELL);
HEADER_CELL.setAttribute('class', 'sort-cta');
HEADER_CELL.innerText = HEADINGS[child];
TABLE.appendChild(TABLE_ROW);
}
} else if (field == 'items') {
for (const child in ITEMS) {
const TABLE_ROW = document.createElement('tr');
let item = ITEMS[child].fields;
let btn = ITEMS[child].button;
// insert the cell data first
for (const row in item) {
const TABLE_DATA = document.createElement('td');
TABLE_ROW.appendChild(TABLE_DATA);
TABLE_DATA.innerText = item[row];
TABLE.appendChild(TABLE_ROW);
}
// then insert the link
if (btn.propURL !== '') {
let link = document.createElement('a');
link.setAttribute('href', btn.propURL);
link.innerHTML = btn.name;
x = TABLE_ROW.insertCell(-1);
x.appendChild(link);
} else {
let link = document.createElement('span');
link.innerHTML = 'Reserved';
x = TABLE_ROW.insertCell(-1);
x.appendChild(link);
}
}
}
}
Related
I have this data and I'm displaying the name. But when I click on, in this case Sweden, I want to display additional info. In the code below I just want to display the country code, but this creates four additional <p> tags because of .forEach loop. That's not really what I want.
How would I go about if I just want to display the country code, and what if I wanted to display all the additional info? I'm kinda stuck as of now.
let data = [
{"name": "Swaziland", "code": "SZ"},
{"name": "Sweden",
"info": [
{"code": "SE"},
{"population": "10.2 million"},
{"area": "447 435km"},
{"capital": "Stockholm"},
{"Language": "Swedish"}]
},
{"name": "Switzerland", "code": "CH"},
{"name": "Syrian Arab Republic", "code": "SY"}
]
let output = '<ul class="searchresultCountries">';
let countries = data;
countries.forEach((value) => {
output += '<li>' + value.name + '</li>';
});
output += '</ul>';
document.querySelector('#countries').innerHTML = output;
document.addEventListener('click', (e) => {
data.forEach((item) => {
if(item.name === e.target.textContent) {
if(item.info) {
item.info.forEach((items) => {
let extraInfo = document.createElement("p");
extraInfo.textContent = items.code;
e.target.appendChild(extraInfo);
});
}
}
});
});
ul {
padding: 0;
}
.searchresultCountries li {
list-style-type: none;
border: 1px solid grey;
margin-bottom: 10px;
padding: 5px;
}
<div id="countries"></div>
You should have some kind of button or link upon which clicking you can show/hide the extra information.
You can try the following way:
let data = [
{"name": "Swaziland", "code": "SZ"},
{"name": "Sweden",
"info": [
{"code": "SE"},
{"population": "10.2 million"},
{"area": "447 435km"},
{"capital": "Stockholm"},
{"Language": "Swedish"}]
},
{"name": "Switzerland", "code": "CH"},
{"name": "Syrian Arab Republic", "code": "SY"}
]
let output = '<ul class="searchresultCountries">';
let countries = data;
countries.forEach((value) => {
output += '<li>' + value.name + '</li>';
});
output += '</ul>';
document.querySelector('#countries').innerHTML = output;
document.addEventListener('click', (e) => {
data.forEach((item) => {
if(item.name === e.target.textContent) {
if(item.info) {
let extraInfo = document.createElement("p");
extraInfo.textContent = item.info[0].code;
e.target.appendChild(extraInfo);
if(item.info.length > 1){
let btnExtra = document.createElement("button");
btnExtra.textContent = "Show More";
e.target.appendChild(btnExtra);
btnExtra.addEventListener('click', function(){
let container = document.createElement("div");
if(!document.querySelector('.extra')){
container.classList.add('extra');
item.info.forEach(function(el, i){
if(i > 0){ // skip the first
let extra = document.createElement("p");
extra.textContent = Object.values(el)[0];
container.appendChild(extra);
}
});
e.target.appendChild(container);
btnExtra.textContent = "Show Less";
}
else{
document.querySelector('.extra').remove();
btnExtra.textContent = "Show More";
}
});
}
}
else{
let extraInfo = document.createElement("p");
extraInfo.textContent = item.code;
e.target.appendChild(extraInfo);
}
}
});
});
ul {
padding: 0;
}
.searchresultCountries li {
list-style-type: none;
border: 1px solid grey;
margin-bottom: 10px;
padding: 5px;
}
<div id="countries"></div>
DEMO
createBtns function create as many buttons as data array is long.
What I want to do is to delete (from DOM) single button when we click on it. The problem is all buttons has the same class, they are all the same, except text value inside of each. There should be a way to get to know which button has been clicked and delete this and only one, but I don't know it.
There is btnClick function which should do it (it alerts for now).
var data = [
{name: "Date", value: "12/31/2018", type: "visible"},
{name: "Car", value: "Ford", type: "visible"},
{name: "Country", value: "Russia", type: "visible"},
{name: "Age", value: "20", type: "visible"},
];
var outer = $(".outerPanel");
var createBtns = () => {
for (var i = 0; i < data.length; i++) {
var btn = $('<div class="btn"></div>');
var name = data[i].name;
var value = data[i].value;
btn.html(name + ": " + value);
btn.click(() => btnClick());
outer.append(btn);
}
}
var btnClick = () => {
alert("test");
}
createBtns();
var data = [
{name: "Date", value: "12/31/2018", type: "visible"},
{name: "Car", value: "Ford", type: "visible"},
{name: "Country", value: "Russia", type: "visible"},
{name: "Age", value: "20", type: "visible"},
];
var outer = $(".outerPanel");
var createBtns = () => {
for (var i = 0; i < data.length; i++) {
var btn = $('<div class="btn"></div>');
var name = data[i].name;
var value = data[i].value;
btn.html(name + ": " + value);
btn.click((e) => btnClick(e));
outer.append(btn);
}
}
var btnClick = (e) => {
e.currentTarget.remove()
}
createBtns();
I assume $ is JQuery?
edit: (from comments)
And if I'd like to also update data array, how would it look like? I mean delete the object from data when button disappears
On this I can think of two kind of approach, the first is to embed the data into the button
var data = [
{name: "Date", value: "12/31/2018", type: "visible"},
{name: "Car", value: "Ford", type: "visible"},
{name: "Country", value: "Russia", type: "visible"},
{name: "Age", value: "20", type: "visible"},
];
var outer = $(".outerPanel");
var createBtns = () => {
for (var i = 0; i < data.length; i++) {
var btn = $('<div class="btn"></div>');
btn[0].data = data[i];
var name = data[i].name;
var value = data[i].value;
btn.html(name + ": " + value);
btn.click((e) => btnClick(e));
outer.append(btn);
}
}
var btnClick = (e) => {
var index = data.indexOf(e.currentTarget.data);
data = data.slice(0,index).concat(data.slice(index+1,data.length));
e.currentTarget.remove()
}
createBtns();
the second approach is just delete the data and re-render the whole thing
var data = [
{name: "Date", value: "12/31/2018", type: "visible"},
{name: "Car", value: "Ford", type: "visible"},
{name: "Country", value: "Russia", type: "visible"},
{name: "Age", value: "20", type: "visible"},
];
var outer = $(".outerPanel");
var createBtns = () => {
for (var i = 0; i < data.length; i++) {
var btn = $('<div class="btn"></div>');
btn[0].data = data[i];
var name = data[i].name;
var value = data[i].value;
btn.html(name + ": " + value);
btn.click((e) => btnClick(e));
outer.append(btn);
}
}
var btnClick = (e) => {
var index = data.indexOf(e.currentTarget.data);
data = data.slice(0,index).concat(data.slice(index+1,data.length));
outer[0].innerHTML = "";
createBtns();
}
createBtns();
If you use const and let (block scoped rather than function scoped), you can simply reference the created btn again inside the handler and .remove() it in the closure:
btn.click(() => btn.remove());
const data = [
{name: "Date", value: "12/31/2018", type: "visible"},
{name: "Car", value: "Ford", type: "visible"},
{name: "Country", value: "Russia", type: "visible"},
{name: "Age", value: "20", type: "visible"},
];
const outer = $(".outerPanel");
const createBtns = () => {
for (let i = 0; i < data.length; i++) {
const btn = $('<div class="btn"></div>');
const name = data[i].name;
const value = data[i].value;
btn.html(name + ": " + value);
btn.click(() => btn.remove());
outer.append(btn);
}
}
createBtns();
.outerPanel {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.btn {
width: 20%;
height: 40px;
border: 2px solid red;
text-align: center;
vertical-align: center;
cursor: pointer;
}
.btn:hover {
background: black;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="outerPanel"></div>
(without const and let, you'd have to use something like this instead - still works, but it's a lot uglier)
You can do this like below:
var btnClick = (e) => {
// get index of clicked button relative to parent element
var index = Array.prototype.indexOf.call(e.target.parentNode.children, e.target);
// remove data entry in array
data.splice(index, 1);
// remove the clicked button
e.target.parentNode.removeChild(e.target);
}
Updated version of your demo:
var data = [{
name: "Date",
value: "12/31/2018",
type: "visible"
},
{
name: "Car",
value: "Ford",
type: "visible"
},
{
name: "Country",
value: "Russia",
type: "visible"
},
{
name: "Age",
value: "20",
type: "visible"
},
];
var outer = $(".outerPanel");
var createBtns = () => {
for (var i = 0; i < data.length; i++) {
var btn = $('<div class="btn"></div>');
var name = data[i].name;
var value = data[i].value;
btn.html(name + ": " + value);
btn.click((e) => btnClick(e));
outer.append(btn);
}
}
var btnClick = (e) => {
// get index of clicked button relative to parent element
var index = Array.prototype.indexOf.call(e.target.parentNode.children, e.target);
// remove data entry in array
data.splice(index, 1);
// refresh displayed text
refreshText();
// remove the clicked button
e.target.parentNode.removeChild(e.target);
}
var refreshText = () => {
document.getElementById("dataText").innerHTML = JSON.stringify(data);
}
createBtns();
refreshText();
.outerPanel {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.btn {
width: 20%;
height: 40px;
border: 2px solid red;
text-align: center;
vertical-align: center;
cursor: pointer;
}
.btn:hover {
background: black;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="outerPanel"></div>
<h3>Data array contents</h1>
<p id="dataText"></p>
Update
removing the btn from DOM instead of CSS change
Solution
You can add an event listener to the button when u create it inside the for loop.
Example code here:
var data = [{
name: "Date",
value: "12/31/2018",
type: "button"
},
{
name: "Car",
value: "Ford",
type: "button"
},
{
name: "Country",
value: "Russia",
type: "button"
},
{
name: "Age",
value: "20",
type: "button"
},
];
const createBtns = () => {
for (var i = 0; i < data.length; i++) {
let btn = document.createElement('input');
btn.setAttribute('class', 'btn');
btn.setAttribute('value', data[i].value);
btn.setAttribute('type', data[i].type);
btn.addEventListener('click', () => {
document.body.removeChild(btn)
});
document.body.appendChild(btn);
}
}
createBtns();
You can try add an event to the button, like this :
function addHideEvent(element) {
for(i=0;i<element.length;i++) {
element[i].onclick = function(e) {
this.remove()
}
}
}
addHideEvent(document.getElementsByClassName("btn"))
<button class="btn"> CLICK HERE </button> </br>
<button class="btn"> CLICK HERE </button> </br>
<button class="btn"> CLICK HERE </button> </br>
<button class="btn"> CLICK HERE </button> </br>
I have a JSON file having the following content.
{
"rooms":[
{
"id": "1",
"name": "living",
"Description": "The living room",
"backgroundpath":"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSrsU8tuZWySrSuRYdz72WWFiYaW5PCMIwPAPr_xAIqL-FgmQ4qRw",
"Settings": {
"Sources": [
{
"srcname":["DirectTV","AppleTV","Sonos"],
"iconpath":["src/assets/images/ThemeEditorImgLib_iTVLight5d3a46c1ad5d7796.png","path2"]
}
],
"hex": "#000"
}
},
{
"id": "2",
"name": "dining",
"Description": "The Dining room",
"backgroundpath":"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTjjspDkQEzbJJ1sSLS2ReWEx5P2ODNQmOtT572OIF9k3HbTGxV",
"Settings": {
"Sources": [
{
"srcname":["Climate","Shades"],
"iconpath":["path1","path2"]
}
],
"hex": "#000"
}
}
]
}
My HTML file Has:
<div class="roww">
<div class="col-md-4 col-sm-6 col-12">
</div>
</div>
I want to display my JSON content in the HTML.
So far I have tried the following.
private initTileGrid():void
{
var col = document.getElementsByClassName("roww")[0];
var outeritems=this.room_list.rooms;
// console.log(outeritems);
for(var i=0;i<outeritems.length;i++){
var tile = document.getElementsByClassName("col-md-4 col-sm-6 col-12 tile no-padding")[0];
var outerdiv = document.createElement("div");
var h5 = document.createElement("h5");
h5.innerHTML = outeritems[i].Description;
outerdiv.appendChild(h5);
var p = document.createElement("p");
p.innerHTML = outeritems[i].name;
outerdiv.appendChild(p);
// col.appendChild(outerdiv);
tile.appendChild(outerdiv);
var inneritem=outeritems[i].Settings.Sources.srcname;
console.log(inneritem);
var innerdiv = document.createElement("div");
for(var j=0;j<inneritem.length;j++)
{
console.log("hi")
var h5inner = document.createElement("h5");
h5inner.innerHTML = inneritem.srcname;
console.log(h5inner);
innerdiv.appendChild(h5inner);
}
tile.appendChild(innerdiv);
}
I am able to display the description and name from the json but not able to fetch the list of sources.
My final solution should be a grid with number of tiles equal to the number of objects in the JSON, with each tile having a background image from the json and its content.
Can anybody tell me where I am going wrong?
Any help appreciated!
I would suggest and recommend generating your dynamic HTML the following way with Template Literals.
Using Array#map, Array#join and Destructuring assignment
const data = {"rooms":[{"id":"1","name":"living","Description":"The living room","backgroundpath":"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSrsU8tuZWySrSuRYdz72WWFiYaW5PCMIwPAPr_xAIqL-FgmQ4qRw","Settings":{"Sources":[{"srcname":["DirectTV","AppleTV","Sonos"],"iconpath":["src/assets/images/ThemeEditorImgLib_iTVLight5d3a46c1ad5d7796.png","path2"]}],"hex":"#000"}},{"id":"2","name":"dining","Description":"The Dining room","backgroundpath":"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTjjspDkQEzbJJ1sSLS2ReWEx5P2ODNQmOtT572OIF9k3HbTGxV","Settings":{"Sources":[{"srcname":["Climate","Shades"],"iconpath":["path1","path2"]}],"hex":"#000"}}]}
const res = data.rooms.map(({name, Description, Settings:{Sources}})=>{
const inner = Sources.map(({srcname})=>{
return srcname.map(src=>`<h5>${src}</h5>`).join("");
}).join("");
return `
<div>
<h5>${Description}</h5>
<p>${name}</p>
<div class="inner">
${inner}
</div>
</div>
`
}).join("");
document.body.innerHTML = res;
body>div{background-color:lightgrey;padding:5px;margin-top:5px}body>div::before{content:"row"}body>div>*{margin-left:10px}h5{background-color:blue;color:white;padding:5px}h5::before{content:"outer h5:: "}p{background-color:purple;color:white;padding:5px}p::before{content:"p:: "}div.inner{padding:5px;background-color:grey}div.inner::before{content:"inner div"}div.inner>h5{background-color:green;color:white}div.inner>h5::before{content:"inner h5:: "}
Unminified CSS:
body > div {
background-color: lightgrey;
padding: 5px;
margin-top: 5px;
}
body > div::before {
content: "row";
}
body > div > * {
margin-left: 10px;
}
h5 {
background-color: blue;
color: white;
padding: 5px;
}
h5::before {
content: "outer h5:: "
}
p {
background-color: purple;
color: white;
padding: 5px;
}
p::before {
content: "p:: ";
}
div.inner {
padding: 5px;
background-color: grey;
}
div.inner::before {
content: "inner div";
}
div.inner > h5 {
background-color: green;
color: white;
}
div.inner > h5::before {
content: "inner h5:: "
}
V_Stack as discussed, this is just the tweak I would do to the sources section of the JSON, moving forward it will make working with a source easier, especially if you add additional properties. Note it is an array of self contained objects now.
{
"rooms": [{
"id": "1",
"name": "living",
"Description": "The living room",
"backgroundpath": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSrsU8tuZWySrSuRYdz72WWFiYaW5PCMIwPAPr_xAIqL-FgmQ4qRw",
"Settings": {
"Sources": [{
"srcname": "DirectTV",
"iconpath": "src/assets/images/ThemeEditorImgLib_iTVLight5d3a46c1ad5d7796.png"
},
{
"srcname": "AppleTV",
"iconpath": "path2"
},
{
"srcname": "Sonos",
"iconpath": ""
}
],
"hex": "#000"
}
},
{
"id": "2",
"name": "dining",
"Description": "The Dining room",
"backgroundpath": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTjjspDkQEzbJJ1sSLS2ReWEx5P2ODNQmOtT572OIF9k3HbTGxV",
"Settings": {
"Sources": [{
"srcname": "Climate",
"iconpath": "path1"
},
{
"srcname": "Shades",
"iconpath": "path2"
}
],
"hex": "#000"
}
}
]
}
Try this:
var col = document.getElementsByClassName("roww")[0];
var outeritems = this.room_list.rooms;
// console.log(outeritems);
for (var i = 0; i < outeritems.length; i++) {
var tile = document.getElementsByClassName("col-md-4")[0];
var outerdiv = document.createElement("div");
var h5 = document.createElement("h5");
h5.innerHTML = outeritems[i].Description;
outerdiv.appendChild(h5);
var p = document.createElement("p");
p.innerHTML = outeritems[i].name;
outerdiv.appendChild(p);
// col.appendChild(outerdiv);
tile.appendChild(outerdiv);
outeritems[i].Settings.Sources.forEach(source => {
var inneritem = source.srcname;
console.log(inneritem);
var innerdiv = document.createElement("div");
for (var j = 0; j < inneritem.length; j++) {
console.log("hi")
var h5inner = document.createElement("h5");
h5inner.innerHTML = inneritem[j];
console.log(h5inner);
innerdiv.appendChild(h5inner);
}
tile.appendChild(innerdiv);
});
}
}
You need to loop through the Settings.Sources and srcname because all of them are arrays
Your main problem starts at this line var inneritem=outeritems[i].Settings.Sources.srcname; Sources is an array so you need to access it like Sources[j] where j is a number within the arrays length.
The inner loop is fine, you just need to loop through Sources properly
I also had to add classes to the tiles class to match your getElementsByClassName query
const room_list = {
"rooms": [{
"id": "1",
"name": "living",
"Description": "The living room",
"backgroundpath": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSrsU8tuZWySrSuRYdz72WWFiYaW5PCMIwPAPr_xAIqL-FgmQ4qRw",
"Settings": {
"Sources": [{
"srcname": ["DirectTV", "AppleTV", "Sonos"],
"iconpath": ["src/assets/images/ThemeEditorImgLib_iTVLight5d3a46c1ad5d7796.png", "path2"]
}],
"hex": "#000"
}
},
{
"id": "2",
"name": "dining",
"Description": "The Dining room",
"backgroundpath": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTjjspDkQEzbJJ1sSLS2ReWEx5P2ODNQmOtT572OIF9k3HbTGxV",
"Settings": {
"Sources": [{
"srcname": ["Climate", "Shades"],
"iconpath": ["path1", "path2"]
}],
"hex": "#000"
}
}
]
}
var col = document.getElementsByClassName("roww")[0];
var outeritems = room_list.rooms;
// console.log(outeritems);
for (var i = 0; i < outeritems.length; i++) {
var tile = document.getElementsByClassName("col-md-4 col-sm-6 col-12 tile no-padding")[0];
var outerdiv = document.createElement("div");
var h5 = document.createElement("h5");
h5.innerHTML = outeritems[i].Description;
outerdiv.appendChild(h5);
var p = document.createElement("p");
p.innerHTML = outeritems[i].name;
outerdiv.appendChild(p);
// col.appendChild(outerdiv);
tile.appendChild(outerdiv);
var inneritems = outeritems[i].Settings.Sources
var innerdiv = document.createElement("div");
for (var j = 0; j < inneritems.length; j++) {
var inneritem = inneritems[j];
var h5inner = document.createElement("h5");
h5inner.innerHTML = inneritem.srcname;
innerdiv.appendChild(h5inner);
}
tile.appendChild(innerdiv);
}
<div class="roww">
<div class="col-md-4 col-sm-6 col-12 tile no-padding">
</div>
</div>
The problem with everything is that the data from the table comes from a database, through an API, so the table is dynamically created and therefore I can not use the CSS for this, remembering that the code below is jotted the data from the table in an array ..
I would like to transform this css below into Javascript, because my table is dynamic and has no way of knowing the amount of tr and td ...
const DATA = {
"Informacoes": {
"qtRows": 3,
"qtCols": 6,
"Cabecalho": ["Id", "Encontro", "Nome", "Preco", "Quantidade", "Total"]
},
"Produtos":[
{
"Id": 200396,
"Encontro": '2017-09-26 01:22',
"Nome": 'Controlador do console de jogos',
"Preco": 22.00,
"Quantidade": 2,
"Total": 44.00
},
{
"Id": 200397,
"Encontro": '2017-09-28 05:57',
"Nome": 'iPhone X',
"Preco":999.00,
"Quantidade": 1,
"Total": 999.00
},
{
"Id": 200398,
"Encontro": '2017-09-29 05:57',
"Nome": 'Samsung S8 Black',
"Preco": 756.00,
"Quantidade": 1,
"Total": 756.00
}],
};
class TableDesktop{
constructor(_id, _arrData){
this.id = _id;
this.arrData = _arrData;
}
set tableObject(_object){ this.table = _object; }
get tableObject( ){ return this.table; }
set theadObject(_object){ this.thead = _object; }
get theadObject( ){ return this.thead; }
set bodyObject(_object){ this.body = _object; }
get bodyObject( ){ return this.body; }
createTable(){
this.generateThead();
this.generateBody();
this.generateTable();
const TABLE_CONTAINER = document.getElementById('table-container');
if(TABLE_CONTAINER.childNodes.length === 1){
TABLE_CONTAINER.removeChild(TABLE_CONTAINER.childNodes[0]);
TABLE_CONTAINER.appendChild(this.tableObject);
} else{
TABLE_CONTAINER.appendChild(this.tableObject);
}
}
generateTable(){
const TABLE = document.createElement('table');
TABLE.setAttribute('class', 'table table100-head');
TABLE.appendChild(this.theadObject);
TABLE.appendChild(this.bodyObject);
this.tableObject = TABLE;
console.log(TABLE)
}
generateThead(){
const TR = document.createElement('tr'),
THEAD = document.createElement('thead');
for(let coluna = 0; coluna < this.arrData.Informacoes.qtCols; coluna++){
const THEAD_VALUES = this.arrData.Informacoes.Cabecalho[coluna];
const TH = document.createElement('th');
TH.setAttribute('scope', 'col');
TH.appendChild(document.createTextNode(THEAD_VALUES));
TR.appendChild(TH);
}
THEAD.setAttribute('class', 'thead-dark');
THEAD.appendChild(TR);
this.theadObject = THEAD;
}
generateBody(){
const BODY = document.createElement('tbody');
let tr;
for(let linha = 0; linha < this.arrData.Informacoes.qtRows; linha++){
const BODY_VALUES = this.arrData.Produtos[linha];
tr = document.createElement('tr');
for(let coluna = 0; coluna < this.arrData.Informacoes.qtCols; coluna++){
const THEAD_VALUES = this.arrData.Informacoes.Cabecalho[coluna];
const TH = document.createElement('th');
const TD = document.createElement('td');
if(THEAD_VALUES === "Id"){
TH.setAttribute('scope', 'row');
TH.appendChild(document.createTextNode(BODY_VALUES.Id));
tr.appendChild(TH);
} else {
TD.appendChild(document.createTextNode(BODY_VALUES[this.arrData.Informacoes.Cabecalho[coluna]]));
tr.appendChild(TD);
}
}
BODY.appendChild(tr);
}
this.bodyObject = BODY;
}
}
const TABLE_DESKTOP = new TableDesktop('container-table-desktop', DATA);
TABLE_DESKTOP.createTable();
table tbody tr td:nth-child(1):before {
content: "";
}
table tbody tr td:nth-child(2):before {
content: "";
}
table tbody tr td:nth-child(3):before {
content: "Name";
}
table tbody tr td:nth-child(4):before {
content: "Price";
}
table tbody tr td:nth-child(5):before {
content: "Quantity";
}
table tbody tr td:nth-child(6):before {
content: "Total";
}
<div id="table-container"></div>
The expected result is this:
https://colorlib.com/etc/tb/Table_Responsive_v1/index.html
This is the relevant part of the code:
const STR = this.arrData.Informacoes.Cabecalho[coluna];
TD.appendChild(document.createTextNode(STR + ': ' + BODY_VALUES[STR]));
const DATA = {
"Informacoes": {
"qtRows": 3,
"qtCols": 6,
"Cabecalho": ["Id", "Encontro", "Nome", "Preco", "Quantidade", "Total"]
},
"Produtos": [{
"Id": 200396,
"Encontro": '2017-09-26 01:22',
"Nome": 'Controlador do console de jogos',
"Preco": 22.00,
"Quantidade": 2,
"Total": 44.00
}, {
"Id": 200397,
"Encontro": '2017-09-28 05:57',
"Nome": 'iPhone X',
"Preco": 999.00,
"Quantidade": 1,
"Total": 999.00
}, {
"Id": 200398,
"Encontro": '2017-09-29 05:57',
"Nome": 'Samsung S8 Black',
"Preco": 756.00,
"Quantidade": 1,
"Total": 756.00
}],
};
class TableDesktop {
constructor(_id, _arrData) {
this.id = _id;
this.arrData = _arrData;
}
set tableObject(_object) {
this.table = _object;
}
get tableObject() {
return this.table;
}
set theadObject(_object) {
this.thead = _object;
}
get theadObject() {
return this.thead;
}
set bodyObject(_object) {
this.body = _object;
}
get bodyObject() {
return this.body;
}
createTable() {
this.generateThead();
this.generateBody();
this.generateTable();
const TABLE_CONTAINER = document.getElementById('table-container');
if (TABLE_CONTAINER.childNodes.length === 1) {
TABLE_CONTAINER.removeChild(TABLE_CONTAINER.childNodes[0]);
TABLE_CONTAINER.appendChild(this.tableObject);
} else {
TABLE_CONTAINER.appendChild(this.tableObject);
}
}
generateTable() {
const TABLE = document.createElement('table');
TABLE.setAttribute('class', 'table table100-head');
TABLE.appendChild(this.theadObject);
TABLE.appendChild(this.bodyObject);
this.tableObject = TABLE;
}
generateThead() {
const TR = document.createElement('tr')
, THEAD = document.createElement('thead');
for (let coluna = 0; coluna < this.arrData.Informacoes.qtCols; coluna++) {
const THEAD_VALUES = this.arrData.Informacoes.Cabecalho[coluna];
const TH = document.createElement('th');
TH.setAttribute('scope', 'col');
TH.appendChild(document.createTextNode(THEAD_VALUES));
TR.appendChild(TH);
}
THEAD.setAttribute('class', 'thead-dark');
THEAD.appendChild(TR);
this.theadObject = THEAD;
}
generateBody() {
const BODY = document.createElement('tbody');
let tr;
for (let linha = 0; linha < this.arrData.Informacoes.qtRows; linha++) {
const BODY_VALUES = this.arrData.Produtos[linha];
tr = document.createElement('tr');
for (let coluna = 0; coluna < this.arrData.Informacoes.qtCols; coluna++) {
const THEAD_VALUES = this.arrData.Informacoes.Cabecalho[coluna];
if (THEAD_VALUES === "Id") {
const TH = document.createElement('th');
TH.setAttribute('scope', 'row');
TH.appendChild(document.createTextNode(BODY_VALUES.Id));
tr.appendChild(TH);
} else {
const TD = document.createElement('td');
const STR = this.arrData.Informacoes.Cabecalho[coluna];
TD.appendChild(document.createTextNode(STR + ': ' + BODY_VALUES[STR]));
tr.appendChild(TD);
}
}
BODY.appendChild(tr);
}
this.bodyObject = BODY;
}
}
const TABLE_DESKTOP = new TableDesktop('container-table-desktop',DATA);
TABLE_DESKTOP.createTable();
/*table tbody tr td:nth-child(1):before {
content: "";
}
table tbody tr td:nth-child(2):before {
content: "";
}
table tbody tr td:nth-child(3):before {
content: "Name";
}
table tbody tr td:nth-child(4):before {
content: "Price";
}
table tbody tr td:nth-child(5):before {
content: "Quantity";
}
table tbody tr td:nth-child(6):before {
content: "Total";
}*/
<link rel="stylesheet" type="text/css" href="https://colorlib.com/etc/tb/Table_Responsive_v1/vendor/bootstrap/css/bootstrap.min.css">
<div id="table-container"></div>
I generate nested div elements based on an object structure. With a click on the parent you can toggle the children.
Now I want to generate a path, separated with slashes, of the click sequence and the "selected" elements. When the user clicks on read -> news -> sport the string path should be "read/news/sport". When the user now clicks on read -> books the path should be now "read/books"
Here is my current version: https://codepen.io/iamrbn/pen/yEqPjG
let path = "";
let object = {
"design": {
"inspiration": {},
"news": {}
},
"read": {
"news": {
"sport": {}
},
"books": {}
},
"code": {}
}
let categoryContainer = document.querySelector(".categoryContainer")
function categoryTree(obj, parent, start = true) {
for (var key in obj) {
let div = document.createElement("div");
div.textContent = key;
div.classList.add("category");
if (parent.children) parent.className += " bold";
if (!start) div.className = "normal hide category";
div.addEventListener('click', function(e) {
e.stopPropagation()
this.classList.toggle('active');
Array.from(div.children).forEach(child => {
child.classList.toggle('hide');
})
})
categoryTree(obj[key], div, false)
parent.appendChild(div)
}
}
categoryTree(object, categoryContainer)
.category {
color: black;
display: block;
line-height: 40px;
background-color: RGBA(83, 86, 90, 0.2);
margin: 8px;
}
.category .category {
display: inline-block;
margin: 0 8px;
padding: 0 8px;
}
.category.hide {display: none;}
.category.normal {font-weight: normal;}
.category.bold {font-weight: bold;}
.category.active {color: red;}
<div class="categoryContainer"></div>
Here's one approach. Your existing code is unmodified except for adding a call to the new getParents() function, which works by crawling up the DOM tree recursively to generate the "path" to the clicked node:
let path = "";
let object = {
"design": {
"inspiration": {},
"news": {}
},
"read": {
"news": {
"sport": {}
},
"books": {}
},
"code": {}
}
let categoryContainer = document.querySelector(".categoryContainer")
function categoryTree(obj, parent, start = true) {
for (var key in obj) {
let div = document.createElement("div");
div.textContent = key;
div.classList.add("category");
if (parent.children) parent.className += " bold";
if (!start) div.className = "normal hide category";
div.addEventListener('click', function(e) {
e.stopPropagation()
this.classList.toggle('active');
Array.from(div.children).forEach(child => {
child.classList.toggle('hide');
})
var thePath = getParents(e.target); // <--- new
console.log(thePath)
})
categoryTree(obj[key], div, false)
parent.appendChild(div)
}
}
function getParents(node, path) {
// Cheat a bit here: we know the textnode we want is the first child node, so we don't have to iterate through all children and check their nodeType:
let thisName = node.childNodes[0].textContent;
path = path ? (thisName + "/" + path) : thisName ;
// iterate to parent unless we're at the container:
if (node.parentNode.className.split(/\s+/).indexOf("categoryContainer") !== -1) {
return path;
} else {
return getParents(node.parentNode, path);
}
}
categoryTree(object, categoryContainer)
.category {
color: black;
display: block;
line-height: 40px;
background-color: RGBA(83, 86, 90, 0.2);
margin: 8px;
}
.category .category {
display: inline-block;
margin: 0 8px;
padding: 0 8px;
}
.category.hide {
display: none;
}
.category.normal {
font-weight: normal;
}
.category.bold {
font-weight: bold;
}
.category.active {
color: red;
}
<div class="categoryContainer"></div>