How to have all symbols in a string without breaking the html? - javascript

I'm playing around with the password generator, but when the string contains a < or > it breaks the HTML and only outputs some of the characters. I'm using innerHTML instead on textContent because I need to wrap each password in a div. Is there another way I can do this without it breaking?
const alphabetUppercase = "abcdefghijklmnopqrstuvwxyz".toUpperCase().split('');
const alphabetLower = "abcdefghijklmnopqrstuvwxyz".split('');
const symbols = "!##$%^&*(>)_+=-`~,./;'[]\|}\"<{:\?".split('');
const numbers = "123456789".split('');
const masterArray = alphabetUppercase.concat(alphabetLower, symbols, numbers);
const passwordButton = document.querySelector('.generate-passwords');
const outputPasswords = document.querySelector('.output-passwords');
passwordButton.addEventListener('click', function(e){
e.preventDefault();
let passwordArray = [];
// number of passwords
let counter = 4;
// Reset text content
outputPasswords.innerHTML = '';
for (let x = 0; x < counter; x++) {
let randomPassword = "";
for (let i = 0; i < 15; i++) {
let randomOutput = Math.floor(Math.random() * masterArray.length);
randomPassword += masterArray[randomOutput];
}
passwordArray.push(randomPassword);
outputPasswords.innerHTML += '<div>' + passwordArray[x] + '</div>';
}
});
<section class="generator">
Generate passwords
<div class="output-passwords"></div>
</section>

You can do something like this:-
const div = document.createElement('div');
div.append(randomPassword);
outputPasswords.append(div);
Instead of using div as a string, create an element "div" and then append it to the parent "outputPasswords" element

Related

How to use for loop to sum a numbers inserted by the user?

i'm trying to create a simple project where the user is prompted to enter how many numbers he would like to add(sum). then when he click the button, a javascript will create a number of input tags equal to the number he inserted and then he will fill them with a number and click another button to calculate the result of the summation and here is the problem. below is a simplified snippet explain what is the problem:
function CL(){
const items = document.getElementById("items");
for (var i = 1; i < 3; i++) {
const inpt = document.createElement("input");
inpt.setAttribute("type","text");
inpt.setAttribute("style","margin:5px;");
inpt.setAttribute("id","y"+i);
inpt.setAttribute("value","");
const newline = document.createElement("br");
items.appendChild(inpt);
items.appendChild(newline);
}
}
function Add(){
const y = 0;
const sum = 0;
var is;
for (var i = 1; i < 3; i++) {
is = i.toString();
y = Number(document.getElementById('y'+ is).value);
sum = sum + y;
}
document.getElementById("demo").innerHTML = sum;
}
in the for loop how can i use getElementById with variables id like item1,item2,item3,...,itemN??
is there other way to achieve what i want?
You can take all items with ID "y" + consecutive number prefix on this way document.getElementById('y' + i).value;
Do not use "Add" for function name and Functions do not have to start with capital letters!
calckStart();
function calckStart() {
const items = document.getElementById("items");
for (var i = 1; i < 3; i++) {
const inpt = document.createElement("input");
inpt.setAttribute("type", "text");
inpt.setAttribute("style", "margin:5px;");
inpt.setAttribute("id", "y" + i);
inpt.setAttribute("value", "");
const newline = document.createElement("br");
items.appendChild(inpt);
items.appendChild(newline);
}
var button = document.createElement('button');
button.innerHTML = 'ClickMe'
items.appendChild(button);
button.addEventListener('click', calculateVal);
}
function calculateVal() {
var res = 0;
for (var i = 1; i < 3; i++) {
res = res + +document.getElementById('y' + i).value;
}
var items = document.getElementById("items");
var result = document.createElement('div');
result.innerHTML = res;
items.appendChild(result);
}
<div id="items"></div>
A better way is ...
When you create elements, you can assign them a CLASS attribute that is one for all input elements. You can then take the values from all elements with this class.
Example:
calckStart();
function calckStart() {
const items = document.getElementById("items");
for (var i = 1; i < 3; i++) {
const inpt = document.createElement("input");
inpt.setAttribute("type", "text");
inpt.setAttribute("style", "margin:5px;");
// inpt.setAttribute("id", "y" + i);
inpt.setAttribute("value", "");
inpt.setAttribute("class", "numbers"); //<-- Set class
const newline = document.createElement("br");
items.appendChild(inpt);
items.appendChild(newline);
}
var button = document.createElement('button');
button.innerHTML = 'ClickMe'
items.appendChild(button);
button.addEventListener('click', calculateVal);
}
function calculateVal() {
var list = document.getElementsByClassName('numbers'); //<-- Get by class
var res = 0;
for (var i = 0; i < list.length; i++) {
res = res + +list[i].value;
}
var items = document.getElementById("items");
var result = document.createElement('div');
result.innerHTML = res;
items.appendChild(result);
}
<div id="items"></div>
You can use ...args to collect arguments and use .reduce to add the arguments together.
const items = document.getElementById("items");
for (var i = 0; i < 3; i++) {
var inpt = document.createElement("input");
inpt.setAttribute("type","number"); //replaced with number
inpt.setAttribute("style","margin:5px;");
inpt.setAttribute("id","y"+i);
inpt.setAttribute("value","");
var newline = document.createElement("br");
items.appendChild(inpt);
items.appendChild(newline); //added newline appending
}
function sum(...args) {
return args.reduce((a, b) => a+b); //reduce arguments
}
<div id="items"></div><br /><button onclick="document.getElementById('answer').textContent = 'answer: ' + sum(+y0.value, +y1.value, +y2.value)">Add</button><div id="answer"></div>

Hide/Show div p5.js

I am using the p5.js library, and I am working on a speech recognition - text to speech project. Kind of a chatbot.
Input is voice input which becomes a string.
I am outputting the result from a txt file, using a markov chain. Output is a string contained in a div.
My question is:
Is there a way to hide/show the div containing my input/output (.myMessage and .robotMessage) in intervals?
I want the whole screen first showing only the input when I am talking, then input disappears and only output showing, then when the computer voice finishes speaking my input is shown in the screen and so on...
Here some parts of the code, let me know if it is clear enough.
//bot
function setup() {
noCanvas();
//reads and checks into the text file
for (var j = 0; j < names.length; j++) {
var txt = names[j];
for (var i = 0; i <= txt.length - order; i++) {
var gram = txt.substring(i, i + order);
if (i == 0) {
beginnings.push(gram);
}
if (!ngrams[gram]) {
ngrams[gram] = [];
}
ngrams[gram].push(txt.charAt(i + order));
}
}
//voice recognition
let lang = 'en-US';
let speechRec = new p5.SpeechRec(lang, gotSpeech);
let continuous = true;
let interim = false;
speechRec.start(continuous, interim);
//text-to-speach
speech = new p5.Speech();
speech.onLoad = voiceReady;
function voiceReady() {
console.log('voice ready');
}
//input-ouput
function gotSpeech() {
if (speechRec.resultValue) {
var p = createP(speechRec.resultString);
p.class('myMessage');
}
markovIt();
chooseVoice();
speech.speak(answer);
}
}
and
function markovIt() {
var currentGram = random(beginnings);
var result = currentGram;
for (var i = 0; i < 100; i++) {
var possibilities = ngrams[currentGram];
if (!possibilities) {
break;
}
var next = random(possibilities);
result += next;
var len = result.length;
currentGram = result.substring(len - order, len);
}
var answer = result;
window.answer = answer;
var p2 = createP(answer);
p2.class('robotMessage');
}
how the HTML looks
<div class="container">
<div class="myMessage"></div>
<div class="robotMessage"></div>
</div>
Use select() to get a document element by its id, class, or tag name. e.g:
let my_div = select("myMessage");
Change the style of an element by style().
e.g hide:
my_div.style("display", "none");
e.g. show:
my_div.style("display", "block");
See also Toggle Hide and Show

How to give unique ids to each child div created dynamically?

The function displays eight elements on click in dynamically created divs using the slice() method. How can I give a unique id to each div? Your suggestions would be of great help to me.
var words = [40];
var count = 0;
var x = "";
function nextElems() {
var newArray = words.slice(count, count + 8);
for (i = 0; i < newArray.length; i++) {
x += '<div class=box>' + newArray[i] + '</div>';
document.getElementById('container').innerHTML = x;
}
x = "";
count += 8;
}
I have tried this but it's not working:
var mainDiv = document.getElementById('container');
var first = mainDiv.getElementsByTagName('div')[0];
first.id = 'one';
You can do it right inside the for loop while it's iterating:
for (i = 0; i < newArray.length; i++)
{
x += '<div id="box-' + i + '"> class="box">' + newArray[i] + '</div>';
document.getElementById('container').innerHTML = x;
}
You can use assign an ID inside the text string.
Here are a couple of other things you can do to improve this code:
Move the getElementById outside the loop
use js methods instead of string concatenation
Something like this (untested):
// get the container
container = document.getElementById('container');
for (i = 0; i < newArray.length; i++)
{
// create a div
var div = document.createElement('div');
// add attributes
div.setAttribute("id", "box-" + i);
div.setAttribute("class", "box");
// create text node
var textnode = document.createTextNode("This is div #" + i);
// add text to div
div.appendChild(textnode);
// append to container
container.appendChild(div);
}
How about giving it the id when creating? Also put the class=box in quotations like so -> class="box".
And add the whole div construct only once after the for loop. Because right now you are basically overwriting the whole thing multiple times.
var words = [40];
var count = 0;
var x = "";
function nextElems() {
var newArray = words.slice(count, count + 8);
for (i = 0; i < newArray.length; i++)
{
// Change class and add custom id
x += '<div class="box" id="box-'+i+'">' + newArray[i] + '</div>';
}
document.getElementById('container').innerHTML = x; // Add divs after for loop
x = "";
count += 8;
}
Now each box has a unique id going from box-0, box-1, ... to box-n

Replacing a div of text with individual spans as letters and iterating through it

I am attempting to replace a div of text with individual span elements of each letter, which is straightforward but I'm trying to have those spans font size increase incrementally and I can't figure out what to throw in the setTimeout function.
<div id ="foo"> Welcome to Here </div>
function test() {
let word = document.getElementById('foo');
let arr = word.split("")
word.innerHTML = "";
arr.forEach((x,index) => {
let newSpan = document.createElement('span')
newSpan.innerHTML = x;
word.appendChild(newSpan);
setTimeout(() => {
????
}, 100 + index*100)
})
}
Do your split on the inner text of your element and the increase the font size of your span:
function test() {
const baseFontSize = 16; // starting font size
const word = document.getElementById('foo');
const text = word.innerText; // split this and not your element object
const arr = text.split("");
word.innerHTML = "";
arr.forEach((x, index) => {
let newSpan = document.createElement('span')
newSpan.innerHTML = x;
word.appendChild(newSpan);
setTimeout(function() {
newSpan.style.fontSize = (baseFontSize + (index * 2)) + 'px'; // increment by 2px
}, 1000 * index) // increment each span a second after the last
})
}
test();
<div id="foo">Welcome to Here</div>
he is another try with settimeout
function test() {
var fontSize = 12;
let word = document.getElementById('foo');
let arr = word.innerHTML.split("")
word.innerHTML = "";
arr.forEach((x,index) => {
var fs = (fontSize + index) +"px";
let newSpan = document.createElement('span')
newSpan.innerHTML = x;
word.appendChild(newSpan);
setTimeout(function(){
newSpan.style.fontSize = fs
}, 2000 + (index * 100));
})
}
test();
span{
display : inline-block;
font-size:12;
}
<div id ="foo"> Welcome to Here </div>
The problem with this code is that getDocumentById() will return a reference to the element, not the text itself.
If the inner content of your div is plain text, you can try this
var domElement = document.getElementById('foo');
var word = domElement.innerText; // Here you get the text itself
domElement.innerText = ''; // Here you clear the previous content which should be text
for (let i = 0; i < word.length; i++) {
var spanElement = document.createElement('span');
spanElement.innerText = word[i];
domElement.appendChild(spanElement);
}
Now if you want to increase the size of the span, you can do it using the counter of the loop as you can see here
spanElement.style.fontSize = i

Logics for store letter in correct place

** I need new logics to store guessed letters in correct place. A game called hangman. As it is now the previous correct letter is overwritten if a new correct guess applys....**
function guessLetter() {
var letter;
var i;
var letterFound;
var correctLettersCount;
correctLettersCount=0;
letterBoxes = "";
letter = this.value;
for (i = 0; i < selectedWord.length; i++) {
if (selectedWord.charAt(i) == letter) { //if
letterBoxes += "<span>" + letter + "</span >";
}
else{
letterBoxes += "<span>*</span>";
}
document.getElementById("letterBoxes").innerHTML = letterBoxes;
}
}
You can use an array that will store the * and letters found
In the following snippet, this array is called display
const wordToFind = "testing";
const wordDisplay = document.getElementById("word");
let display = Array.from('*'.repeat(wordToFind.length));
wordDisplay.innerHTML = display.join("");
function checkLetter(el){
const letter = el.value.toLowerCase();
for(let i=0,l=wordToFind.length;i<l;i++){
if(wordToFind[i]===letter)
display[i] = letter;
}
el.value = "";
wordDisplay.innerHTML = display.join("");
}
<input oninput="checkLetter(this)" />
<p id="word"></p>

Categories

Resources