I have an script that prints each letter of an string and how many times it is printed, but it is not working properly, it overrides the last letter. For example: when you type in the textarea "assist" it should print the following: a: 1 s: 3 i: 1 t: 1 But it only prints: t: 1 How to print properly the string?
function ex44() {
let string = document.getElementById("sarc4").value
string = string.toLowerCase();
const count = {}
string.split("").forEach(ch => {
if (!count[ch]) {
count[ch] = 1
return
}
count[ch]++
})
for (const key in count) {
document.getElementById("result4").innerHTML = `${key} : ${count[key]}`
}
}
<label for="sarcina4"> Enter text</label>
<br>
<textarea name="sarcina4" id="sarc4" cols="60" rows="5"></textarea>
<br>
<button onclick="ex44()">Afisare</button>
<p id="result4"></p>
document.getElementById("result4").innerHTML = `${key} : ${count[key]}`
Will override the innerHTML
.
Consider 'adding' the content using appendChild
or insertAdjacentHTML
:
Is it possible to append to innerHTML without destroying descendants' event listeners?
const res = document.getElementById("result4");
for (const key in count) {
res.insertAdjacentHTML('beforeend', `<p>${key} : ${count[key]}</p>`);
}
function ex44() {
let string = document.getElementById("sarc4").value
string = string.toLowerCase();
const count = {}
string.split("").forEach(ch => {
if (!count[ch]) {
count[ch] = 1
return
}
count[ch]++
})
const res = document.getElementById("result4");
for (const key in count) {
res.insertAdjacentHTML('beforeend', `<p>${key} : ${count[key]}</p>`);
}
}
<label for="sarcina4"> Enter text</label>
<br>
<textarea name="sarcina4" id="sarc4" cols="60" rows="5"></textarea>
<br>
<button onclick="ex44()">Afisare</button>
<p id="result4"></p>
Note: I've wrapped the ${key} : ${count[key]}
inside a <p></p>
tag so we see each letter on a separate row
Another option is to create an output
string by using map
and join
like so:
const output = Object.keys(count).map((key) => `<p>${key} : ${count[key]}</p>`);
document.getElementById("result4").innerHTML = output.join('');
function ex44() {
const input = document.getElementById("sarc4").value.toLowerCase();
const count = {}
input.split("").forEach(ch => {
if (!count[ch]) {
count[ch] = 1;
} else {
count[ch]++
}
});
const output = Object.keys(count).map((key) => `<p>${key} : ${count[key]}</p>`);
document.getElementById("result4").innerHTML = output.join('');
}
<label for="sarcina4"> Enter text</label>
<br>
<textarea name="sarcina4" id="sarc4" cols="60" rows="5">test</textarea>
<br>
<button onclick="ex44()">Afisare</button>
<p id="result4"></p>
Cache your elements, and then use textContent
to update the element text using string concatenation.
const sarc4 = document.getElementById('sarc4');
const result4 = document.getElementById('result4');
function ex44() {
string = sarc4.value.toLowerCase();
const count = {};
string.split("").forEach(ch => {
if (!count[ch]) {
count[ch] = 1;
return;
}
count[ch]++
});
let result = '';
for (const key in count) {
result += `${key}:${count[key]} `;
}
result4.textContent = result;
}
<label for="sarcina4"> Enter text</label>
<br>
<textarea name="sarcina4" id="sarc4" cols="60" rows="5"></textarea>
<br>
<button onclick="ex44()">Afisare</button>
<p id="result4"></p>
Move the document.getElementById("result4").innerHTML
outside the loop.
You are rewritting the innerHTML
of the element with id result4
each time the loop is executing. You can update the innerHTML by appending the new striing with existing by using below to get the issue fixed.
document.getElementById("result4").innerHTML += `${key} : ${count[key]}`
The above implementation cannot be considered as a good implementation even though it's fixes your problem. Accessing DOM elements directly from script is always costly. If it's inside a loop a loop it's definitely more costly.
Instead of accessing the DOM element multiple time from a loop, you could create the template string inside the loop and assign the innerHTML
only once as below. This will be better in terms of performance.
function ex44() {
let string = document.getElementById("sarc4").value
string = string.toLowerCase();
let template = '';
const count = {}
string.split("").forEach(ch => {
if (!count[ch]) {
count[ch] = 1
return
}
count[ch]++
})
for (const key in count) {
template += `${key} : ${count[key]}`
}
document.getElementById("result4").innerHTML = template;
}
<label for="sarcina4"> Enter text</label>
<br>
<textarea name="sarcina4" id="sarc4" cols="60" rows="5"></textarea>
<br>
<button onclick="ex44()">Afisare</button>
<p id="result4"></p>