I am having an issue with populating an HTML table with the correct data dynamically via javascript and jQuery.
The table shows some numbers based on gender, and every time the user makes a selection, they get back new data from the server, which populates the table. There are two rows and 4 cells. I dynamically insert the cells and update the text via javascript every time the API returns new data. The problem is that the data is being populated in the wrong table cells -- the number for "female / cell 2" ends up in the "female / cell 3" and so forth. I can't figure out how to target the correct cells based on the data. Here is a minimal reproduction via codepen, or see below for code as well:
Also I did look at the following threads but didn't see anything that seemed like it addressed my issue:
s/o thread 1 ----- s/o thread 2
The data is very simple and looks like this -- there are positive, neutral, and negative percentages for female and male:
let genderData = [
{ gender: "female", percent: 36, score: "neutral" },
{ gender: "female", percent: 1, score: "negative" },
{ gender: "female", percent: 18, score: "positive" },
{ gender: "male", percent: 27, score: "neutral" },
{ gender: "male", percent: 14, score: "positive" },
{ gender: "male", percent: 1, score: "negative" }
];
The HTML table looks like this, with the header row hard-coded in HTML:
<!-- Gender Table -->
<table id="sentiment-table__gender" class="table">
<thead class="sticky">
<tr id="sentiment-gender-tr">
<!-- gender -->
<th class="sticky left-align table-th">Gender</th>
<!-- percent positive posts -->
<th class="sticky right-align table-th">Positive Posts</th>
<!-- percent neutral posts -->
<th class="sticky right-align table-th">Neutral Posts</th>
<!-- percent Negative posts -->
<th class="sticky right-align table-th">Negative Posts</th>
</tr>
</thead>
<tbody id="sentiment-page-table__body"></tbody>
</table>
What I need to do is populate the table with the percentages for each sentiment, categori开发者_运维技巧zed by gender. The "female" item with a "neutral" score of "36%" should appear in the female row / cell 2 (neutral), but instead appears in a different cell. I suspect this is because the data is not in a specific order, so I can't just populate the cells one by one. I can't change anything about the backend or how the data is returned.
I loop through the data, and then write conditionals to separate the female and male data. Then I write a switch statement based on the sentiment and insert cells for each item. I know what I'm missing is some way to specify which cell the data point should be inserted into. I tried specifying it by saying newFemaleRow.insertCell(2)
(or whichever cell I wanted to target), but that threw an error:
sentiment.js:280 Uncaught DOMException:
Failed to execute 'insertCell' on 'HTMLTableRowElement':
The value provided (2) is outside the range [-1, 1].
See below for a full snippet including my JS, and here's that codepen link one more time too.
$(function () {
populateTable();
});
let genderData = [
{ gender: "female", percent: 36, score: "neutral" },
{ gender: "female", percent: 1, score: "negative" },
{ gender: "female", percent: 18, score: "positive" },
{ gender: "male", percent: 27, score: "neutral" },
{ gender: "male", percent: 14, score: "positive" },
{ gender: "male", percent: 1, score: "negative" }
];
const populateTable = () => {
// Local variables
let genderTable = $("#sentiment-table__gender");
// Store table id in variable
let tableRef = document.getElementById("sentiment-table__gender");
// Clear out table data before loading new results
$(tableRef).find("tr:gt(0)").remove();
let newMaleRow = tableRef.insertRow(-1);
let newFemaleRow = tableRef.insertRow(-1);
let maleGenderCell = newMaleRow.insertCell(0);
let maleGenderText = document.createTextNode("Male");
maleGenderCell.className = "left-align";
maleGenderCell.appendChild(maleGenderText);
let femaleGenderCell = newFemaleRow.insertCell(0);
let femaleGenderText = document.createTextNode("Female");
femaleGenderCell.className = "left-align";
femaleGenderCell.appendChild(femaleGenderText);
// Loop through the data to populate the table
for (let item of genderData) {
// MALE
if (item.gender === "male") {
switch (item.score) {
case "negative":
let negativeMalePostsCell = newMaleRow.insertCell();
let negativeMalePostsText = document.createTextNode(
item.percent.toLocaleString("en-US") + "%"
);
negativeMalePostsCell.className = "right-align";
negativeMalePostsCell.appendChild(negativeMalePostsText);
break;
case "neutral":
let neutralMalePostsCell = newMaleRow.insertCell();
let neutralMalePostsText = document.createTextNode(
item.percent.toLocaleString("en-US") + "%"
);
neutralMalePostsCell.className = "right-align";
neutralMalePostsCell.appendChild(neutralMalePostsText);
break;
case "positive":
let positiveMalePostsCell = newMaleRow.insertCell();
let positiveMalePostsText = document.createTextNode(
item.percent.toLocaleString("en-US") + "%"
);
positiveMalePostsCell.className = "right-align";
positiveMalePostsCell.appendChild(positiveMalePostsText);
break;
}
}
// FEMALE
if (item.gender === "female") {
switch (item.score) {
case "negative":
let negativeFemalePostsCell = newFemaleRow.insertCell();
let negativeFemalePostsText = document.createTextNode(
item.percent.toLocaleString("en-US") + "%"
);
negativeFemalePostsCell.className = "right-align";
negativeFemalePostsCell.appendChild(negativeFemalePostsText);
break;
case "neutral":
let neutralFemalePostsCell = newFemaleRow.insertCell();
let neutralFemalePostsText = document.createTextNode(
item.percent.toLocaleString("en-US") + "%"
);
neutralFemalePostsCell.className = "right-align";
neutralFemalePostsCell.appendChild(neutralFemalePostsText);
break;
case "positive":
let positiveFemalePostsCell = newFemaleRow.insertCell();
let positiveFemalePostsText = document.createTextNode(
item.percent.toLocaleString("en-US") + "%"
);
positiveFemalePostsCell.className = "right-align";
positiveFemalePostsCell.appendChild(positiveFemalePostsText);
break;
}
}
}
};
/* ==================================================
Table styling
================================================== */
.table {
text-overflow: wrap;
border-collapse: collapse;
border-spacing: 0;
width: 80%;
border: 1px solid #ddd;
position: relative;
}
/* GENERAL TABLE STYLING */
.sticky {
position: sticky;
position: -webkit-sticky;
top: -1px;
background: white;
}
.table-th,
.table td {
padding: 8px;
height: 40px;
}
.right-align {
text-align: right;
}
.center-align {
text-align: center;
}
.left-align {
text-align: left;
}
.table tr:nth-child(even) {
background-color: orange;
}
.border {
border-bottom: 1px inset black;
}
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<!-- jQuery UI -->
<script src="https://code.jquery.com/ui/1.13.1/jquery-ui.js"></script>
<!-- Gender Table -->
<table id="sentiment-table__gender" class="table">
<colgroup>
<col span="1" />
<col span="1" />
<col span="1" />
<col span="1" />
</colgroup>
<thead class="sticky">
<tr id="sentiment-gender-tr">
<!-- gender -->
<th class="sticky left-align table-th">Gender</th>
<!-- percent positive posts -->
<th class="sticky right-align table-th">Positive Posts</th>
<!-- percent neutral posts -->
<th class="sticky right-align table-th">Neutral Posts</th>
<!-- percent Negative posts -->
<th class="sticky right-align table-th">Negative Posts</th>
</tr>
</thead>
<tbody id="sentiment-page-table__body"></tbody>
</table>
Shoot, this should have been easy. I simply need to insert the JS dynamically in the same order as the HTML! All I did was switch around the order of the cases in the switch statement to match the order of the cells in the table header, and boom, all the data populated in the correct cell.
Here is an updated codepen
$(function () {
populateTable();
});
let genderData = [
{ gender: "female", percent: 36, score: "neutral" },
{ gender: "female", percent: 1, score: "negative" },
{ gender: "female", percent: 18, score: "positive" },
{ gender: "male", percent: 27, score: "neutral" },
{ gender: "male", percent: 14, score: "positive" },
{ gender: "male", percent: 1, score: "negative" }
];
const populateTable = () => {
// Local variables
let genderTable = $("#sentiment-table__gender");
// Store table id in variable
let tableRef = document.getElementById("sentiment-table__gender");
// Clear out table data before loading new results
$(tableRef).find("tr:gt(0)").remove();
let newMaleRow = tableRef.insertRow(-1);
let newFemaleRow = tableRef.insertRow(-1);
let maleGenderCell = newMaleRow.insertCell(0);
let maleGenderText = document.createTextNode("Male");
maleGenderCell.className = "left-align";
maleGenderCell.appendChild(maleGenderText);
let femaleGenderCell = newFemaleRow.insertCell(0);
let femaleGenderText = document.createTextNode("Female");
femaleGenderCell.className = "left-align";
femaleGenderCell.appendChild(femaleGenderText);
// Loop through the data to populate the table
for (let item of genderData) {
// MALE
if (item.gender === "male") {
switch (item.score) {
case "neutral":
let neutralMalePostsCell = newMaleRow.insertCell();
let neutralMalePostsText = document.createTextNode(
item.percent.toLocaleString("en-US") + "%"
);
neutralMalePostsCell.className = "right-align";
neutralMalePostsCell.appendChild(neutralMalePostsText);
break;
case "negative":
let negativeMalePostsCell = newMaleRow.insertCell();
let negativeMalePostsText = document.createTextNode(
item.percent.toLocaleString("en-US") + "%"
);
negativeMalePostsCell.className = "right-align";
negativeMalePostsCell.appendChild(negativeMalePostsText);
break;
case "positive":
let positiveMalePostsCell = newMaleRow.insertCell();
let positiveMalePostsText = document.createTextNode(
item.percent.toLocaleString("en-US") + "%"
);
positiveMalePostsCell.className = "right-align";
positiveMalePostsCell.appendChild(positiveMalePostsText);
break;
}
}
// FEMALE
if (item.gender === "female") {
switch (item.score) {
case "neutral":
let neutralFemalePostsCell = newFemaleRow.insertCell();
let neutralFemalePostsText = document.createTextNode(
item.percent.toLocaleString("en-US") + "%"
);
neutralFemalePostsCell.className = "right-align";
neutralFemalePostsCell.appendChild(neutralFemalePostsText);
break;
case "negative":
let negativeFemalePostsCell = newFemaleRow.insertCell();
let negativeFemalePostsText = document.createTextNode(
item.percent.toLocaleString("en-US") + "%"
);
negativeFemalePostsCell.className = "right-align";
negativeFemalePostsCell.appendChild(negativeFemalePostsText);
break;
case "positive":
let positiveFemalePostsCell = newFemaleRow.insertCell();
let positiveFemalePostsText = document.createTextNode(
item.percent.toLocaleString("en-US") + "%"
);
positiveFemalePostsCell.className = "right-align";
positiveFemalePostsCell.appendChild(positiveFemalePostsText);
break;
}
}
}
};
/* ==================================================
Table styling
================================================== */
.table {
text-overflow: wrap;
border-collapse: collapse;
border-spacing: 0;
width: 80%;
border: 1px solid #ddd;
position: relative;
}
/* GENERAL TABLE STYLING */
.sticky {
position: sticky;
position: -webkit-sticky;
top: -1px;
background: white;
}
.table-th,
.table td {
padding: 8px;
height: 40px;
}
.right-align {
text-align: right;
}
.center-align {
text-align: center;
}
.left-align {
text-align: left;
}
.table tr:nth-child(even) {
background-color: orange;
}
.border {
border-bottom: 1px inset black;
}
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<!-- jQuery UI -->
<script src="https://code.jquery.com/ui/1.13.1/jquery-ui.js"></script>
<!-- Gender Table -->
<table id="sentiment-table__gender" class="table">
<colgroup>
<col span="1" />
<col span="1" />
<col span="1" />
<col span="1" />
</colgroup>
<thead class="sticky">
<tr id="sentiment-gender-tr">
<!-- gender -->
<th class="sticky left-align table-th">Gender</th>
<!-- percent neutral posts -->
<th class="sticky right-align table-th" id='neutral-posts-th'>Neutral Posts</th>
<!-- percent Negative posts -->
<th class="sticky right-align table-th" id='negative-posts-th'>Negative Posts</th>
<!-- percent positive posts -->
<th class="sticky right-align table-th" id='positive-posts-th'>Positive Posts</th>
</tr>
</thead>
</table>
精彩评论