Javascript: manipulate data inside data attributes in HTML - javascript

I have a html/js code that takes data from a json and render it to html table. It has been working fine for a while. Recently the number of items being handled has greatly increased and can't afford to put data statically into html anymore. So I have changed the code in html and I'm now using data attributes, and a JS that loops through each item from the json file and writes it to the correct data attribute in html. It works.
I have another JS file that scans through all td cells and if a condition is met the text in the cell turns red, or purple. Else it remains standard black. This used to work, but not anymore.
This is the new html code implemented:
`
<table id="table" align="center" render-area="reboot">
<thead>
<tr>
<th class="text-center" data-tsorter="input-text">
Server Name
<img src='/icons/sort.png' width='20' height='20' style='display:inline;'>
</th>
<th class="text-center" data-tsorter="numeric">
Last Boot
<img src='/icons/sort.png' width='20' height='20' style='display:inline;'>
</th>
</tr>
</thead>
<tbody render-action="loop">
<tr render-data="json">
<td>{!Server Name!}</td>
<td>{!Last Boot!}</td>
</tr>
</tbody>
</table>
`
and here below the JS that does not work anymore:
`
const today = new Date();
const todayMonth = (today.getMonth())+1;
const todayDay = today.getDate();
// Query all table cells in document
document.querySelectorAll('table td').forEach(function(td) {
const srvDay = parseInt(td.innerHTML.split('/')[1]); // day
if(Number.isInteger(srvDay)){
const srvMonth = parseInt(td.innerHTML.split('/')[0]); //month
// If date contained in td text before current date then apply red background style
if(srvDay != todayDay || srvMonth != todayMonth){
td.style.color = "red";
}
}
if((td.innerHTML.split(' ')[0]).includes('unreachable')){
td.style.color = "purple";
}
});
`
if I examine that table td through the console, I get that the td html is !Last Boot! and that is why I believe the JS above does not work anymore. But if I look at the Elements console, I see that the DOM has all td correctly filled. In fact all works fine, except the JS above. The question is: how to manipulate data that is filled using data attributes? If I use a class for that td I get the same. Any hint?
UPDATE: I've found that when data is dynamically assigned it goes into an HTMLCollection, which I can now read as I found out which attribute to use to select the correct html element. In fact it contains the data I need, with the td cells filled in.
But! don't know how to operate this htmlcollection. I've tried and I'm getting weird results. I've learnt that on htmlcollection foreach does not work. Either transform it into array with Array.from() or use for of loop. When I use any of the two I lose the data and again I get the placeholder {!Last Boot!}. This is how far I got:
`
function tdTextHandler(renderArea){
const today = new Date();
const todayMonth = (today.getMonth())+1;
const todayDay = today.getDate();
const newArr = document.querySelectorAll(`[render-area="${renderArea}"]`);
newArr.forEach(function(e) {
const newArr4 = (Array.from(e.children))[1].children
console.log(newArr4);
for (item of newArr4) {
console.log(item);
const srvDay = parseInt(item.innerHTML.split('/')[1]); // day
if(Number.isInteger(srvDay)){
const srvMonth = parseInt(item.innerHTML.split('/')[0]); //month
// If date contained in td text before current date then apply red background style
if(srvDay != todayDay || srvMonth != todayMonth){
item.style.color = "red";
}
}
if((item.innerHTML.split(' ')[0]).includes('unreachable')){
item.style.color = "purple";
}
};
`
the first console.log tells me that I have a htmlcollection and in the console I can see that its entries have the data. But the second console.log shows that the data is gone, although the structure is there and I'm back to the placeholder.

Solved. As the table is dynamically generated by another JS script, it is in that script (and in its loop) that the JS code above is to be placed.

if you have something like:
<div data-myAttribute="1"></div>
<div data-myAttribute="2"></div>
...
you select them :
const els = document.querySelectAll('div[data-myAttribute');
els.forEach(e => {
...
})

Related

Pure JavaScript - Update just one cell in entire Html table

I have a rest call in my application (spring based) to update the User's Active (boolean) status using Fetch API like below:
async function activateUser(obj) {
var fullURL = obj.getAttribute("href");
let response = await fetch(fullURL, {
method: 'POST'
});
let result = await response.json();
if (response.ok) {
alert(result.username + " Activated Successfully.. !!");
obj.parentElement.parentElement.cells[6].innerHTML = "true";
//getAllUsersApi(endpoint);
} else {
alert(response.status + "Error Occurred.. !!");
}
}
All works well.
Now, I am trying to update just that cell of my html table to true whose Initial value was false. I am updating the html table's cell by hard-coding the column number using (as you can see above too) - obj.parentElement.parentElement.cells[6].innerHTML = "true";. I was wondering if there is some way we can find the false in that row for that particular user and update that cell only. Prior to this I was reloading the entire table (the commented line in the JS code above), which nobody will prefer. I tried to find the solution here and here. But couldn't find the stating point for my situation.
From my rest call I am returning the User object so I was just wondering if I could search the table (on client side) just for that particular user and update that just one corresponding cell. In the table Id, Username and email are unique if that helps to find and replace false to true..
Summarized question: How can I update just one cell of my html table by utilizing the response from my REST call?
Since each ID is unique, you can add that to each row as an id="user id goes here" attribute. Then each cell can be given a class to specify it's purpose.
For example:
<table>
<tr id="user_{{ user ID }}">
<td class="user-name">{{ user name }}</td>
<td class="user-email">{{ user email address }}</td>
<td class="is-user-active">{{ user active status }}</td>
</tr>
</table>
Since the result is returning the username, I am guessing it can also return the ID, in which case your code would look like this:
if (response.ok) {
let isUserActive = document.querySelector(`#user_${result.id} .is-user-active`);
isUserActive.innerHTML = "true"
}
There is not really much magic to do. Instead of targetting cell 6, you would check find out the column number by finding the column header that has the title "Enabled". Replace this:
obj.parentElement.parentElement.cells[6].innerHTML = "true";
With:
let row = obj.closest("tr");
let titles = row.closest("table").querySelectorAll("th");
for (let cellNo = 0; cellNo < titles.length; cellNo++) {
if (titles[cellNo].textContent.includes("Enabled")) {
row.cells[cellNo].textContent = "true";
}
}
This is based on the information you have given in the question (not behind links) and in comments/chat.

using queryselector to get textContent from td tags without class names

I am trying to create a datascraper using node.
Here is a sample html code for an item that I am trying to scrape:
<tr class="cool">
<td>Todd</td>
<td>Bob eats shoes <br/>[Stack]
</tr>
Here is some code that I am using to extract:
cars.forEach(carCard=> {
const carCool = {
number: carCard.querySelector('?').textContent,
date: carCard.querySelector('?').textContent,
};
});
I was wondering if there was anyway I could get the text of 'Todd' and [Stack] using this query selector. I do not know what I would need to put in place of the question marks. If not is there a different method I can use to accomplish this?
Please help.
You could do the following:
// To get all the td fields
const tds = document.querySelectorAll('td');
// to get the content of the td fields
tds.forEach(td => {
console.log(td.textContent);
})

Show table data on another page in a table HTML

My problem is the following:
I have created an array from a table I already have and stored the column I want into an array, and then stored it in the localStorage using JSON.stringify:
function createArray(){
var arrayPlayerName = [];
var count = 1;
while(count<=playerNum){
arrayPlayerName.push(document.getElementById('playertable').rows[count].cells[1].innerHTML);
count++;
}
localStorage.setItem("playerNameArray", JSON.stringify("arrayPlayerName"));
}
(playerNum is a variable with a fixed number used in other methods, and the "getElementById" works).
After that I want to show this data in another table in another HTML doc.
So, the following is my HTML code:
<table class="myTable">
<thead>
<tr class="row">
<th colspan="3">Array List</th>
</tr>
</thead>
</table>
And this is the script:
var storedPlayerArray = JSON.parse(localStorage.getItem("playerNameArray"));
tablegenerate (storedPlayerArray);
function tablegenerate (list) {
for(i=0; i<playerNum;i++){
var $formrow = '<tr><td>'+list[i]+'</td></tr>';
$('.myTable').append($formrow);
}
}
I am not sure what I'm doing wrong.. thanks in advance.
EDIT: I am calling the createArray function with a button, and I'm navigating to the second page with another button. The second page should load directly.
EDIT2: I have revised that the array is being stored and called properly on the second page, so the issue is now on the "tablegenerate" function.
EDIT
I think I found the problem try this:
var storedPlayerArray = JSON.parse(localStorage.getItem("playerNameArray"));
function tablegenerate (list) {
for(var i=0; i<list.length;i++){
var $formrow = $('<tr><td>'+list[i]+'</td></tr>');
$('.myTable').append($formrow);
}
}
$(document).ready(function(){
tablegenerate (storedPlayerArray);
})
You have an issue in your createArray function.. You are running JSON.stringify on a string instead of the array you want to store.
Change this:
localStorage.setItem("playerNameArray", JSON.stringify("arrayPlayerName"));
To this:
localStorage.setItem("playerNameArray", JSON.stringify(arrayPlayerName));

How to automatically call a JavaScript that modify a value before show this value?

I am very new in JavaScript and I have the following problem to solve.
I have a table that contains this td cell:
<td class= "dateToConvert" width = "8.33%">
<%=salDettaglio.getDataCreazione() != null ? salDettaglio.getDataCreazione() : "" %>
</td>
This retrieve a String from an object and show it into the cell
The problem is the retrieved string represent a date having the following horrible form: 20131204 and I have to convert it into the following form: 2013-12-04.
So I am thinking to create a JavaScript that do this work when the value is retrieved.
My problem is: how can I do to automatically call the JavaScript before to show the value into the td cell? (So I show the modified output in the desidered form)
EDIT 1:
So I have create thid JavaScript function into my page:
function convertData() {
var tds = document.querySelectorAll('.dateToConvert');
[].slice.call(tds).forEach(function(td) {
td.innerText = td.innerText.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3');
});
}
But it don't work because it never enter in this function (I see it using FireBug JavaScript debugger). Why? What am I missing? Maybe have I to call it explicitly in some way in my td cell?
Of course it is better to fix backend method to make it return proper format. But since you have no control over it try to use something like this:
var tds = document.querySelectorAll('.dateToConvert');
[].slice.call(tds).forEach(function(td) {
td.textContent = td.textContent.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3');
});
Check the demo below.
var tds = document.querySelectorAll('.dateToConvert');
[].slice.call(tds).forEach(function(td) {
td.textContent = td.textContent.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3');
});
<table>
<tr>
<td class= "dateToConvert" width = "8.33%">
20131204
</td>
<td class= "dateToConvert" width = "8.33%">
20140408
</td>
</tr>
</table>

Javascript, creating a template for a textfield with subscript and superscript

I am rather new to JavaScript. In my experimentation with some sample code, I have created an html file which contains a table. In one of the table data fields I have a text type field. Is there a way to make a button that inserts a pre-defined template for entry that allows for manipulation? aka I press a button "money" that inputs an additional formatted text to "$0.00".
so for example
function input_button(){
var template = "$0.00"
var my_txt = document.getElementById("money");
my_txt.value += Template;
On a side note, what if I wanted to use subscript and superscript? I have tried utilizing the .sup() and .sub() methods, but it just inserts the tags and doesn't alter the aesthetics of the text. ( so in the table, it looks like
<sub> things to be subscript </sub>
opposed to
things to be subscript
I'm not familiar with any way to template text formats, so you might just have to hard code in the logic. As to your second question, when you use the .sup and .sub methods, are you inserting the result in the inner html? For example:
function helloWorldSuper(){
var str = "Hello World";
var result = str.sup();
document.getElementById("tableCell").innerHTML = result;
}
To apply a mask to the input field in order to auto-format values with a template you will need to listen to input key press events and handle according to your mask. There are some scripts that already do this, like Masked Input Plugin for jQuery.
If you want the input text to just have $0.00 as an initial value, it's quite easy to do.
You can create and insert a row into the table via JavaScript like this:
<html>
<body>
<button id="insertRowButton">Insert</button>
<table>
<thead>
<tr><th>Text</th><th>Input</th></tr>
</thead>
<tbody id="tableBody">
</tbody>
</table>
<script>
(function() {
// Elements used
var tableBody = document.getElementById('tableBody'),
insertRowButton = document.getElementById('insertRowButton');
// Create a new row template
function createRow() {
var tr = document.createElement('tr'),
tdText = document.createElement('td'),
tdInput = document.createElement('td'),
sub = document.createElement('sub'),
input = document.createElement('input'),
text = document.createTextNode('This is a text node '),
subscriptText = document.createTextNode('with subscript');
sub.appendChild(subscriptText);
tdText.appendChild(text);
tdText.appendChild(sub);
input.value = '$0.00';
tdInput.appendChild(input);
tr.appendChild(tdText);
tr.appendChild(tdInput);
return tr;
}
// Insert a new row into table
function insertRow() {
var tr = createRow();
tableBody.appendChild(tr);
}
// Bind events
insertRowButton.addEventListener('click', insertRow);
}());
</script>
</body>
</html>
Here is it at JSFiddle: http://jsfiddle.net/ck7qargw/
I'm a little confused but I'm making the assumption that you are trying to add sup/sub script via innerHTML?
var template = "<span class='supStyle'>$0.00</span>"
CSS:
.supStyle{vertical-align:top;font-size:smaller;}
Or, you can use a forloop:
mySup = document.getElementsByClassName("supStyle");
for (var i=0;i<mySup.length;i++)
{
mySup[i].style.verticalAlign = "sub";
mySup[i].style.fontSize = "smaller";
}

Categories

Resources