Displaying HTML Element Count - javascript

I'm doing Free Code Camp projects with User Stories requiring a minimum number of different elements.
I came up with the idea of using some of the page to display an element count and thought it would be simple to implement. Famous last words I know.
Spent a few hours reviewing MDN , W3, W3Schools, ... examples and documentation. Also searched here.
I've tried using botj javascript and jQuery and can get results in javascript but they are incorrect. The jQuery stuff doesn't work at all.
<head>
<script src=
"https://code.jquery.com/jquery-2.2.4.min.js">
</script>
<script src=
"https://code.jquery.com/jquery-3.5.0.js">
</script>
</head>
<body>
<!-- much deletia -->
<div class="ToC">
<div>
<table>
<tr>
<th colspan="2">HTML Element Use</th>
</tr>
<tr>
<td>Name</td><td>Count</td>
</tr>
<tr>
<td>Total</td><td><script>document.write(HTMLCollection.length)</script></td>
</tr>
<tr>
<td>p</td><td><script>document.write(document.getElementsByTagName('p').length);</script></td>
</tr>
<tr>
<td>div</td><td><script>document.write($( div ).length;)</script></td>
</tr>
</table>
</div>
</div>
<!-- even more deletia -->
</body>
What am I doing wrong?

var divCnt = document.getElementsByTagName('div').length
var pCnt = document.getElementsByTagName('p').length
var tCnt = document.getElementsByTagName('*').length
document.getElementById('total').innerHTML = tCnt;
document.getElementById('div').textContent = divCnt;
document.getElementById('p').innerHTML = pCnt;
<head>
<script src=
"https://code.jquery.com/jquery-2.2.4.min.js">
</script>
<script src=
"https://code.jquery.com/jquery-3.5.0.js">
</script>
</head>
<body>
<!-- much deletia -->
<div class="ToC">
<div>
<table>
<tr>
<th colspan="2">HTML Element Use</th>
</tr>
<tr>
<td>Name</td><td>Count</td>
</tr>
<tr>
<td>Total</td><td id='total'></td>
</tr>
<tr>
<td>p</td><td id='p'></td>
</tr>
<tr>
<td>div</td><td id='div'></td>
</tr>
</table>
</div>
</div>
<!-- even more deletia -->
</body>

This gets all of the elements from a simple document.querySelectorAll('*') which matches everything. Calling that returns a NodeList, so you want to turn that into an array using Array.from(...).
The next line uses the Array reduce method to turn that array of many elements into a single map.
It does that by using the node tagName as the key into the map, and assigning the node to that key. Actually it has to create an array on the map element first, so it can push all of the similar nodes onto that array.
That is done by using the element type name, such as DIV, as the key into the map. If that's the first time a node type has been seen it creates the array and then, in all cases, pushes the Element into the array.
let allelements = Array.from(document.querySelectorAll('*'));
let result = allelements.reduce(function(map, obj) {
if (map[obj.tagName] == null) {
map[obj.tagName] = [];
}
map[obj.tagName].push(obj);
return map;
}, {});
console.log(result);
<div id="div-one">
<p>one</p>
<p>two</p>
</div>
<div id="div-two">
<p>three</p>
<p>four</p>
<p>five</p>
</div>
You can then iterate the map keys to find how many of each element type there is.
If all you care about is the total element count you can skip reducing the array and just use allelements.length which tells you how many total nodes were selected.
Notice this gets ALL elements! You can limit it to just the <body> elements by first selecting the body and then using querySelectorAll on that.
In this example I've also added summarizing the number of each element type to the console.
let body = document.querySelector('body');
let allelements = Array.from(body.querySelectorAll('*'));
let result = allelements.reduce(function(map, obj) {
if (map[obj.tagName] == null) {
map[obj.tagName] = [];
}
map[obj.tagName].push(obj);
return map;
}, {});
console.log('Resulting map =', result);
console.log('Counts:');
for (tag of Object.keys(result)) {
console.log(tag.toLowerCase(), result[tag].length);
}
<div id="div-one">
<p>one</p>
<p>two</p>
</div>
<div id="div-two">
<p>three</p>
<p>four</p>
<p>five</p>
</div>

Related

Looking for a localStorage solution for simple table editing (page HTML included)

I'm trying to build a 'tool' (beina mainpage with a menu, and a few subpages with some tables) for composing answers from prewritten bits for me and my work collagues. I'd do with just html editing on my own, but I'd like to make a couple of improvements on it for them... not that I know how to, despite trying.
I found a nice, editable table on stack/jsfiddle and can get it to run, yet the saving doesn't work.
It allsows for editing of cells, and adding rows. Delete I don't care much for.
I tried to copy with some form of getElementBy, but failed miserably.
Trying to auto-add the buttons in the next row doesn't work either.
Here's codepen. https://codepen.io/pen/?template=vYGRKvZ
Any input will be appreciated.
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="/css/result-light.css">
<style id="compiled-css" type="text/css">
.editable{ background:#EAEAEA}
.clEdit
{
width : 200px; /*Try chaging it as per need*/
overflow : hidden; /* try scroll with more height */
height : 15px;/*Try chaging it as per need*/
}
</style>
<script id="insert"></script>
</head>
<body>
<table class="table table-striped" id="ConTable" border="1">
<thead>
<tr>
<th>#</th>
<th>tag</th>
<th>button(s)?</th>
<th>text to copy</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td><div class="clEdit" contenteditable="true">welcome</div></td>
<td><button id="copy">©copy next</button><br><button id="save">☑save all</button></td>
<td><div class="clEdit" contenteditable="true">lorem ipsum</div></td>
</tr>
<td>2</td>
<td><div class="clEdit" contenteditable="true">another tag</div></td>
<td><button id="copy">©copy next</button><br><button id="save">☑save all</button></td>
<td><div class="clEdit" contenteditable="true">lorem ipsum</div></td>
</tr>
<td>3</td>
<td><div class="clEdit" contenteditable="true">welcome</div></td>
<td><button id="copy">©copy next</button><br><button id="save">☑save all</button></td>
<td><div class="clEdit" contenteditable="true">lorem ipsum</div></td>
</tr>
</tbody>
</table>
</div>
<button id="copy">©copy next</button>
<button id="save">☑save all</button>
<button id="add">Add Rows</button>
<button id="del">Delete Rows</button>
<div id="divCon">
</div>
<script type="text/javascript">//<![CDATA[
$(".clEdit").prop('contenteditable',true);
//Try with hover replace click with hover
$(".clEdit").hover(function(e){
$(this).prop("title",$(this).html());
});
var idFirstCol = 3;
$("#add").click(function(){
//LOGIC TO ADD ROW TO TABLE
var trRow = "<tr><td>"+ ++idFirstCol
+ "</td><td>"+ "SecondColValue" +"</td><td><div class='clEdit'>"+ "ThirdColValue" +"</div></td>s <td> "+ "LastColValue"+" </td></tr>";
$("#ConTable").append(trRow);
$(".clEdit").hover(function(e){
$(this).prop("title",$(this).html());
});
$(".clEdit").prop('contenteditable',true); });
//]]></script>
<script>
// tell the embed parent frame the height of the content
if (window.parent && window.parent.parent){
window.parent.parent.postMessage(["resultsFrame", {
height: document.body.getBoundingClientRect().height,
slug: "8mt6d7bz"
}], "*")
}
// always overwrite window.name, in case users try to set it manually
window.name = "result"
</body></html>
If you're trying to save the table data to localStorage, this is how I would do it.
I'd use an array of key-value pairs, this is what it would look like...
const tableDataArray = [
{
tag: 'some tag stuff',
buttons: 'some button stuff',
text: 'some text'
},
{
tag: 'some more tag stuff',
buttons: 'some more button stuff',
text: 'some more text'
}
];
When dealing with localStorage I would...
grab the array from local storage, if it exists... or I would create an array in localStorage (array typically is empty but you can put some default rows in if you want)
Populate the table with the data saved in the array I just got from localStorage.
When a user adds or deletes a row, I would add/delete that row from the array in your code, not from localStorage.
When a user hits 'save' I would then save the array from the code to local storage, overwritting what was in localStorage with the new updated array.
FOR #2.
After grabbing the saved array from localStorage, I'd loop through the array adding each element in the object to the respective column.
for (let i = 0, i < tableDataArray.length, i++) {
// determine which row you're adding to then...
secondColValue = tableDataArray[i].tag;
thirdColValue = tableDataArray[i].buttons;
lastColValue = tableDataArray[i].text;
}

Generate QR Codes several time with name tags and logos

I need to generate QR codes to create IDs.
I have the following div for the ID design:
<div class="row">
<div class="col-sm-6">
<table id="tb">
<tr><th style="font-size: 2em">Name:</th></tr>
<tr><th style="font-size: 2em">Date of Birth:</th></tr>
<tr><th style="font-size: 2em" id="qrcode"></th></tr>
</table>
</div>
</div>
And I have 2 text boxes. The first one is to specify the number of QR needed, the second for the text that should be coded inside the QR:
<script src="./jquery.min.js"></script>
<script src="./qrcode.min.js"></script>
<script type="text/javascript">
var total = $("#number_of_card").val();
var startingFrom = $("#start_number").val();
while(total!==0)
{
$(this).append('tb')
var codedId = parseInt(total)+parseInt(startingFrom);
new QRCode(document.getElementById("qrcode"), ""+codedId);
total--;
}
</script>
I used the following library: QR Code.
What I need is to duplicate all the div so each qr code generated should have a name and date of birth div, which I can not reach.
The full script is here:
https://jsfiddle.net/w2qgbjLf/
Your fiddle had an error, so you were not seeing QRs, see this fiddle.
https://jsfiddle.net/gv9dx1sh/16/
var total = $("#number_of_card").val();
var startingFrom = $("#start_number").val();
while(total !== 0)
{
$('body').append(`<div><div>Name:</div><div>BirthDate</div><div id='qrcode${total}'></div></div>`);
var codedId = parseInt(total)+ parseInt(startingFrom);
new QRCode(document.getElementById(`qrcode${total}`), "" + codedId);
total--;
}

why changing classname in a list of object removes itens from the list

You will see that only 2 td object lost the clasNname. Why the variable "many" looses a itens at each className=""? Can anyone help me? Thank you.
<!DOCTYPE html>
<html>
<head>
<title>Why?</title>
<style>
.f{background:lightblue;}
.g{background:lightcoral;}
</style>
</head>
<body>
<table id="t" style="border:1px solid black">
<tr>
<td class="f">1</td>
<td class="f">2</td>
<td class="f">3</td>
<td class="f">4</td>
</tr>
</table>
<script>
many = document.getElementById("t").getElementsByClassName("f");
document.write("initial length of many="+many.length+"<br>");
for (var x = 0; x < many.length; x++) {
many[x].className='';
document.write("loop x="+x+" many.length="+many.length+"<br>");
}
document.write("final length of many="+many.length+"<br>");
</script>
</body>
</html>
The getElememtsByClassName() method returns a live NodeList, therefore if you remove the class-name you searched by those elements that no longer have that class-name are immediately removed from that NodeList held in the many variable.

How to add hyperlink in array (Javascript)

I have a random quote generator script, and I need to add hyperlinks for each quote. The issue - I can't figure out how to accomplish this for the life of me.
I'm a novice in javascript but after searching around, thinking there's an easy solution to my problem, I can't find a workable answer to this.
How do I go about adding a hyperlink in an array? I'd appreciate this. It's probably so simple too.
Here's the page to the random quote generator, and I posted the code below. Thank you. https://www.hscripts.com/scripts/JavaScript/random-quote-generator.php
I posted the code below as well.
<style>
.row {
padding-left: 10px;
background-color: white;
font-family: verdana, san-serif;
font-size: 13px;
}
</style>
<!-- Script by hscripts.com -->
<script type="text/javascript">
var arr = new Array();
arr.push("Javascript is different from Java");
arr.push("Javascript is different from Java");
arr.push("Javascript is different from Java");
arr.push("CSS - Cascading Style Sheet");
arr.push("HTML is a platform independent language");
function rotate() {
var num = Math.round(Math.random() * 3);
add(num);
}
function add(i) {
var chi = document.createTextNode(arr[i]);
var tab1 = document.getElementById("add1");
while (tab1.hasChildNodes()) {
tab1.removeChild(tab1.firstChild);
}
tab1.appendChild(chi);
}
</script>
<!-- Script by hscripts.com -->
<table align=center style="background-color:#C0C0C0">
<tr>
<td background-color:#c0c0c0 align=center width=300 style="font-family:Times New Roman;">
<b>Random Quote Generator</b>
</td>
</tr>
<tr>
<td id=add1 class=row width=300 align=center>Click Next to Display Random message</td>
</tr>
<tr>
<td align=center>
<input type=button value="Next" border=0 onclick="rotate()">
</td>
</tr>
</table>
You can keep html code in your array e.g.
arr.push('CSS');
But I don't prefer mix html code with js.
Look at my solution on JSFiddle https://jsfiddle.net/xoL2bbtd/
I little modified your array and add function
function add(i) {
var chi = document.createElement('a');
chi.textContent = arr[i].text;
chi.setAttribute('href', arr[i].link);
var tab1 = document.getElementById("add1");
if (tab1.hasChildNodes()) {
tab1.removeChild(tab1.firstChild);
}
tab1.appendChild(chi);
}
I create anchor element and set href attribute. In array I keep object which contains text and link property
And one more thing. Create array by using new Array is slower than using []. Check this https://jsperf.com/new-array-vs-literal/15

Can't make JavaScript work, is it an ID issue?

I'm trying to get a message to appear when a user clicks the image that's in a the "lifeCalculatorButton" ID, but I can't figure out how to make it work. I know that the html doc is referencing the js doc fine, so that's not the issue. Any ideas?
<html>
<head>
<link rel="Stylesheet" type="text/css" href="apps.css" />
<script type="text/javascript" src="apps.js"></script>
<title>my apps</title>
</head>
<body>
<div id="breaks">
<a href="http://info" > <img src="homeicon.png" /> </a>
<br>
<br>
<br>
<br>
<br>
<div id="appTable" style="float: left">
<table border="0" id="appTable">
<tr>
<td>life calculator</td>
</tr>
<tr>
<td>punny!</td>
</tr>
<tr>
<td>drink roulette (on its way!)</td>
</tr>
</table>
</div>
<div id="arrowTable" style="float: left">
<table border="0">
<tr>
<td id="lifeCalculatorButton"><img src="arrow1.png" width="45"</td>
</tr>
<tr>
<td id="punnyButton"><img src="arrow1.png" width="45"/></td>
</tr>
<tr>
<td id="drinkRouletteButton"><img src="arrow1.png" width="45"/></td>
</tr>
</table>
</div style="clear: both">
<div id="content">
my apps :)
</div>
And here's the JavaScript:
var foo = document.getElementById('lifeCalculatorButton');
foo.onClick = function (){
document.getElementById('content').innerHTML = 'foo';
};
Try changing the onclick event to all lowercase.
var foo = document.getElementById('lifeCalculatorButton');
foo.onclick = function (){
document.getElementById('content').innerHTML = 'foo';
};
EDIT
The below code works in both Firefox and IE. I've changed the event from foo.onClick to foo.onclick. Make sure your javascript block is at the end of the page or the call to getElementById will return null. Also, you should close the unclosed <img> tag and remove the style="clear: both" from the second to last closing </div> near the bottom of your page.
<html>
<head>
<link rel="Stylesheet" type="text/css" href="apps.css" />
<title>my apps</title>
</head>
<body>
<div id="breaks">
<img src="homeicon.png" />
<br /><br /><br /><br /><br />
<div id="appTable" style="float: left">
<table border="1" id="appTable">
<tr><td>life calculator</td></tr>
<tr><td>punny!</td></tr>
<tr><td>drink roulette (on its way!)</td></tr>
</table>
</div>
<div id="arrowTable" style="float: left">
<table border="1">
<tr><td id="lifeCalculatorButton"><img src="arrow1.png" width="45"/></td></tr>
<tr><td id="punnyButton"><img src="arrow1.png" width="45"/></td></tr>
<tr><td id="drinkRouletteButton"><img src="arrow1.png" width="45"/></td></tr>
</table>
</div>
<div id="content">
my apps :)
</div>
</body>
</html>
<script type="text/javascript">
var foo = document.getElementById('lifeCalculatorButton')
foo.onclick = function (){
document.getElementById('content').innerHTML = 'foo';
};
</script>
EDIT
If you are using an external javascript file you must use the window.onload event handler to register your handler to ensure the page has completely loaded.
window.onload = function () {
var foo = document.getElementById('lifeCalculatorButton')
foo.onclick = function (){
document.getElementById('content').innerHTML = 'foo';
};
};
First, you seem to have a typo here:
<td id="lifeCalculatorButton"><img src="arrow1.png" width="45"</td>
The <img> tag is not closed properly.
You also have to either move the <script> include at the bottom of your document or attach to the window load event to make sure that your script is executed after the elements in question appear in the DOM:
window.onload = function () {
var foo = document.getElementById("lifeCalculatorButton");
// ...
};
It may be overkill but this could be a good excuse to introduce yourself to jQuery or similar framework. It makes this kind of work trivial to implement. See this fiddle for a working examlpe using jQuery.
If you don't want to use jQuery your javascript looks ok as this fiddle works.
As others have said make sure you are not assigning the event handler until after the DOM is loaded. This is done in the pure javascript fiddle above using the following code
<script type='text/javascript'>//<![CDATA[
window.onload=function(){
var foo = document.getElementById('Clickable');
foo.onclick = function (){
alert("See It Works");
};
}//]]>
On a side note following a comment above, the cursor will not change on hover as the browser is still interpreting the element as what ever it is, in this case, a table cell. The only difference is that it now has an event assigned to it. To have the cursor change you will need to do this using CSS.
Does it need to be the td that holds the id? Why not use an a tag to wrap around the image (and as suggested close the img tag correctly with />). Apply the onclick to the a tag and call a function with a return false afterwords to bypass normal behavior... and obviously, in your onclick you can call whatever function u want

Categories

Resources