Input is blank after I update text in mirroring div - javascript

I am trying to create a very basic markdown editor. I am using a textarea on the left to type in data, and on the right, I have an entry point div where I'm storing everything I type in as I type it using a "keyup" listener. I have gotten the text to apply a class to make it bold when the code is formatted with * at the beginning and end of a word, but after the DOM is updated with this the next word I try to type in doesn't get added and is in fact showing up as blank when I run it through a debugger.
Here is the JS I have currently...
const html = document.querySelector('#html-area');
const md = document.querySelector('#markdown-area');
html.addEventListener("keyup", function(e) {
md.innerHTML = e.target.value;
const words = md.innerHTML.split(' ');
const len = words.length;
for(let i = 0; i < len; i++) {
// if the first character is * and the last character is * and the length of the current word is greater than or equal to 2 then change that word by adding the ".bold" class to it.
if(words[i][0] === "*" && words[i][words[i].length - 1] === "*" && words[i].length >= 2){
const indexOfWord = md.innerHTML.split(' ').indexOf(words[i]);
const newWord = md.innerHTML.split(' ')[indexOfWord] = ` <span class="bold">${md.innerHTML.split(' ')[indexOfWord]}</span> `;
const before = md.innerHTML.split(' ').slice(0, indexOfWord).join();
md.innerHTML = before + newWord;
break;
}
}
});
And here is my HTML...
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link rel="stylesheet" href="./css/index.css" />
<title>MarkDown</title>
</head>
<body>
<!-- HTML -->
<div id="app">
<div id="html-container">
<h2>HTML</h2>
<section>
<label for="html-area"></label>
<textarea
name="html-area"
placeholder="type html here..."
id="html-area"
></textarea>
</section>
</div>
<!-- Markdown -->
<section id="markdown-container">
<h2>MarkDown</h2>
<div>
<div
id="markdown-area"
>Markdown text will show here...</div>
</div>
</section>
</div>
<script src="./index.js"></script>
</body>
</html>
Thanks for any tips or help.

One thing: here
md.innerHTML = before + newWord;
you're cutting the output with the newWord. You need to define some after similar to before, and md.innerHTML = before + newWord + after;.
Although a better solution would be to do: split - map - join. Split the input text into words, map them into either original or bold version, and join back. Something like this:
const html = document.querySelector("#html-area");
const md = document.querySelector("#markdown-area");
const bold = word =>
`<span class="bold">${word.substring(1, word.length - 1)}</span>`;
const boldOrNot = word =>
word.startsWith("*") && word.endsWith("*") && word.length > 2
? bold(word)
: word;
html.addEventListener("keyup", function(e) {
const input = e.target.value;
const output = input.split(" ").map(boldOrNot).join(" ");
md.innerHTML = output;
});
https://codepen.io/anon/pen/jRrxZx

Related

Why doesn't my element update during the else part but during the if part?

I'm making a program where it has a collection of calculators, and for some reason when I try to change the innerhtml of a certain text it only changes it during the if statement and not during the else part.
function Palindrome() {
//Fix not changing to processing when doing new palindrome.
var Division = 0;
var input = document.getElementById("PalindromeInput").value;
var GiveAnswer = document.getElementById("PalindromeAnswer");
var Answer = String(input);
while (0 < 1) {
if (Answer == Answer.split("").reverse().join("")) {
GiveAnswer.innerHTML = `That is a palindrome of the ${Division}th Division.`;
break
} else {
GiveAnswer.innerHTML = `Processing...`;
Division = Division + 1;
Answer = String(parseInt(String(Answer)) + parseInt(Answer.split("").reverse().join("")));
};
};
};
https://replit.com/#ButterDoesFly/Arcane-Calculators#index.html
I'm not sure but I guess the reason for this is that the function never goes to the else part because it gets break every time. Remember that .reverse() reverses the array in place so the if statement will always be true. Try to add different variable for the reversed answer.
function Palindrome() {
//Fix not changing to processing when doing new palindrome.
var Division = 0;
var input = document.getElementById("PalindromeInput").value;
var GiveAnswer = document.getElementById("PalindromeAnswer");
var Answer = String(input);
GiveAnswer.innerHTML = `Processing...`;
setTimeout(()=>{
while (0 < 1) {
if (Answer == Answer.split("").reverse().join("")) {
GiveAnswer.innerHTML = `That is a palindrome of the ${Division}th Division.`;
break
} else {
Division = Division + 1;
Answer = String(parseInt(String(Answer)) + parseInt(Answer.split("").reverse().join("")));
};
};
},1000)
};
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>replit</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<p id="PalindromeAnswer">This will tell you the number its at and then the answer.</p>
<input type="text" id="PalindromeInput" placeholder="What number would you like to enter?">
<br>
<input type="button" onclick="Palindrome()" value="Submit" id="PalindromeButton">
<script src="script.js"></script>
<!--
This script places a badge on your repl's full-browser view back to your repl's cover
page. Try various colors for the theme: dark, light, red, orange, yellow, lime, green,
teal, blue, blurple, magenta, pink!
-->
<script src="https://replit.com/public/js/replit-badge.js" theme="blue" defer></script>
</body>
</html>
result is rendering very fast such that changes are not reflecting in ui..add a timeout so that changes reflect in front end

Javascript if else statement. Variables in HTML stored in Javascript

I am trying to make an event when two numbers randomly generated are equal.So I need to store values in a variable in javascript and see if they are equal.
if (target_number == you_score){
console.log(1)
}
I have put console.log in there to test if the statement is executed
const button = document.querySelector('target_number')
function getRandomNumber() {
return Math.floor(Math.random() * 10)
}
function getRandomNumber2() {
return Math.floor(Math.random() * 10)
}
function getRandomNumber3() {
return Math.floor(Math.random() * 10)
}
document.getElementById("target_number").addEventListener("click", displayGuess);
function displayGuess(){
document.getElementById("target_number").innerHTML = getRandomNumber();
}
document.getElementById("target_number").style.cursor = "pointer";
document.getElementById("computer_score").addEventListener("click", displayGuess2);
function displayGuess2(){
document.getElementById("computer_score").innerHTML = getRandomNumber2()
}
document.getElementById("computer_score").style.cursor = "pointer";
document.getElementById("you_score").addEventListener("click", displayGuess3);
function displayGuess3(){
document.getElementById("you_score").innerHTML = getRandomNumber3()
}
document.getElementById("you_score").style.cursor = "pointer";
var computerScore = document.getElementById("computer_score")
var youScore = document.getElementById("you_score")
var targetNumber = document.getElementById("target_number")
Here is my HTML. I would like to make a if else statement in script that checks if the value of target_number and computer_score are equal
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Number Guesser</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div>
<h1>Number Guesser</h1>
</div>
<div>
<h2>Round
<span class="round_number">1</span>
</h2>
</div>
<h3>Target Number: <span id="target_number">Blank</span></h3>
</body>
<div class="container">
<div class="computer">Computer
<div>Score <span id="computer_score">0</span></div>
</div>
<div class="you">You
<div>Score <span id="you_score">0</span></div>
</div>
</div>
<h1 id="new">New</h1>
<script src="script.js"></script>
</html>
Based on what it looks like you mean, I have simplified your code using event delegation, some css and a single function to generate a random number lower than 10.
const someNumberLT10 = () => Math.floor(Math.random() * 10);
document.addEventListener(`click`, handle);
function handle(evt) {
if (evt.target.id === "play") {
// ^ button#play was clicked
const youNr = someNumberLT10();
const computerNr = someNumberLT10();
// two random numbers < 10 are generated and stored into variables
document.querySelector(`#you_score`).textContent = youNr;
document.querySelector(`#computer_score`).textContent = computerNr;
// ^ numbers are displayed
document.querySelector(`#equal`).textContent = `Equal? ${
youNr === computerNr ? `Yes! 😊` : `Nope ... 😔`}`;
// ^ score (equal or not) is displayed
const round = document.querySelector(`[data-round]`);
round.dataset.round = +round.dataset.round + 1;
// ^ round index is set
}
}
[data-round]:after {
content:' 'attr(data-round);
}
<h2 data-round="1">Round</h2>
<!-- data-round is a so called data attribute. It can be used as a variable
in js (dataset). Here, js is used to set the value, and css is used
to display the value ([data-round]:after) -->
<h3>Target Number: <button id="play">Create</button></h3>
<div class="container">
<div>Computer score <span id="computer_score">0</span></div>
<div>Your score <span id="you_score">0</span></div>
<div id="equal"></div>
</div>

How to change the innerHTML of the char js

I want to make a Hangman game so I can learn JavaScript, I don't know how to change the innerHTML
of the char I made in js. So when I know if the string includes the guess then i want to make the line which represents the correct guess to transform into a charater and make it apear but when i run the code it turns the last of the lines into the correct guess and makes it disapear when there's a new guess and transforms the line into second correct guess. And doesn't reconizez 'o'(the last character that is in the string)
I would like to apologize if I made grammer mistakes.
//defineing the word
var a = 'hello';
// makes the lines
for ( var i=0; i<a.length; i++){
var letter = document.createElement("h3");
letter.className = 'letter'+i;
var j = 2*i+23;
letter.style ="position: absolute;"+"top: 14%;"+"left: "+j+"%;";
letter.innerHTML = "_";
document.body.appendChild(letter);
}
//submit btn gets the input and if it's correct shows it, if it isn't correct than puts into a wrong words
function submt(a,letter){
var inpt = document.getElementById('input');
if (a.includes(inpt.value)){
letter.innerHTML = a[a.indexOf(inpt.value)];
}else {
console.log('wrong')
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hangman</title>
<link rel="stylesheet" href="style.css">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Yanone+Kaffeesatz:wght#500&display=swap" rel="stylesheet">
</head>
<body>
<p class='letter'>Write the letter in here:</p>
<p class='bad'> the wrong letters:</p>
<p class='word'>the word:</p>
<input type="text" class="input" id="input">
<button class="sub" id='submit' onclick="submt(a,letter)">submit</button>
<script src="script.js"></script>
</body>
</html>
You were resetting the letter variable to the last h3 element. You needed a array for each of the slots.
//defineing the word
var a = 'hello';
// makes the lines
var letters = []; // this array store the h3 elements
for ( var i=0; i<a.length; i++){
var letter = document.createElement("h3");
letter.className = 'letter'+i;
var j = 2*i+23;
letter.style ="position: absolute;"+"top: 14%;"+"left: "+j+"%;";
letter.innerHTML = "_";
document.body.appendChild(letter);
letters.push(letter); // add element to array
}
//submit btn gets the input and if it's correct shows it, if it isn't correct than puts into a wrong words
function submt(a,letter){
var inpt = document.getElementById('input');
if (a.includes(inpt.value)){
var l = 0, result = [];
while (l<a.split('').length) {
if (a.split('')[l] == inpt.value) { // a split('') turns the word into an array so it is easier to search
result.push(l); // this store the position of the correct letter in the word
}
l++;
}
var l = 0;
while (l<result.length) {
letters[result[l]].innerHTML = a.split('')[result[l]]; // change the h3 elements content to the correct letter using the result array.
l++;
}
}else {
console.log('wrong')
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hangman</title>
<link rel="stylesheet" href="style.css">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Yanone+Kaffeesatz:wght#500&display=swap" rel="stylesheet">
</head>
<body>
<p class='letter'>Write the letter in here:</p>
<p class='bad'> the wrong letters:</p>
<p class='word'>the word:</p>
<input type="text" class="input" id="input">
<button class="sub" id='submit' onclick="submt(a,letter)">submit</button>
<script src="script.js"></script>
</body>
</html>
You are currently accessing always the last dash created.
Thats because createElement will create a h3 element for each char in the word.
for ( var i=0; i<a.length; i++){
var letter = document.createElement("h3");
...
}
After the loop the variable var letter will contain the last h3 element created. You defined letter inside a for loop but access it inside a method.
It works in javascript but is a bit unexpected to see.
I assume you are not yet familiar with scopes. That is okay for now but maybe also something you want to read about for future progress.
https://www.w3schools.com/js/js_scope.asp
A solution close to your solution, but which uses an array to save all h3 elements.
Note that I also removed the parameters of submt() because you did not use them.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hangman</title>
<link rel="stylesheet" href="style.css">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Yanone+Kaffeesatz:wght#500&display=swap" rel="stylesheet">
</head>
<body>
<p class='letter'>Write the letter in here:</p>
<p class='bad'> the wrong letters:</p>
<p class='word'>the word:</p>
<input type="text" class="input" id="input">
<button class="sub" id='submit' onclick="submt()">submit</button>
<script src="script.js"></script>
</body>
</html>
//defineing the word
var a = 'hello';
// makes the lines
var letters = []
for ( var i=0; i<a.length; i++){
var letter = document.createElement("h3");
letter.className = 'letter'+i;
var j = 2*i+23;
letter.style ="position: absolute;"+"top: 14%;"+"left: "+j+"%;";
letter.innerHTML = "_";
document.body.appendChild(letter);
letters.push(letter)
}
function submt(){
var inpt = document.getElementById('input');
if (a.includes(inpt.value)){
var index = a.indexOf(inpt.value)
letters[index].innerHTML = a[index];
}else {
console.log('wrong')
}
}

Prevent Backspace and Delete from being "handled" by input event in vanilla JS

I am trying to create a simple program that adds "hyphens" automatically to a text input field. The goal is to add hyphens at the 5th, 9th and 14th character. Aside from that it should only allow numbers, which it does by "replacing" anything typed by an empty string.
Now it works fine : if you type something, no problem, the hyphens get added and only the numbers are taken into account. When you copy / paste a string (either by ctrlcmd + C / ctrlcmd + v or right click copy / paste), it removes the characters not allowed by the ReGex and place the hyphens at the right spot. However, when I try and delete the hyphens, it doesn't work. I guess that, looking at my code, the hyphens get removed, so the string now being 4, 9 or 14 chars long, the hyphens get automatically added again as soon as it's removed.
I have tried replacing the input listener by a keyup, keypress, or keydown, which is fine if I simply return a false result from the function when the event.key is either backspace or delete, but then, the right click copy paste doesn't work anymore, which I want it to.
Is there a way for me to listen for any input, using the input event listener, except the backpsace or del key ? Any other ideas ? I'd like a vanilla JS answer (though I guess a jQuery one could be useful to someone else).
Here is my code :
const selectConfirmBtn = document.querySelector(".confirm");
const selectSNInput = document.querySelector(".serial-number");
let serialNumberLength;
let serialNumber;
selectSNInput.addEventListener("input", function(event) {
// if (event.key === "Backspace" || event.key === "Delete") {
// return false;
// }
selectSNInput.value = selectSNInput.value.replace(/[^0-9]/g, "");
console.log(selectSNInput.value);
console.log(selectSNInput.value.length);
if (selectSNInput.value.length >= 4) {
selectSNInput.value =
selectSNInput.value.substring(0, 4) +
"-" +
selectSNInput.value.substring(4, selectSNInput.value.length);
if (selectSNInput.value.length >= 9) {
selectSNInput.value =
selectSNInput.value.substring(0, 9) +
"-" +
selectSNInput.value.substring(9, selectSNInput.value.length);
}
if (selectSNInput.value.length >= 14) {
selectSNInput.value =
selectSNInput.value.substring(0, 14) +
"-" +
selectSNInput.value.substring(14, selectSNInput.value.length);
}
}
if (selectSNInput.value.length == 19) {
selectConfirmBtn.disabled = false;
} else {
selectConfirmBtn.disabled = true;
}
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<label>Enter a serial number!
<input type="text" value="" class="serial-number">
</label>
<input class="confirm" type="button" value="confirm" disabled><br>
<div class="message"></div>
<script src="js/condition.js"></script>
</body>
</html>
You are suffixing - to 4th digit, instead you could try prefixing to 5th digit i.e. insert - only when 5th digit is available like below.
const selectConfirmBtn = document.querySelector(".confirm");
const selectSNInput = document.querySelector(".serial-number");
let serialNumberLength;
let serialNumber;
selectSNInput.addEventListener("input", function(event) {
const splitByLen = 4;
const value = selectSNInput.value.replace(/[^0-9]/g, "");
let result = [],
start = 0,
end = 0;
do {
end = start + splitByLen > 12 ? start + value.length : start + splitByLen;
const subValue = value.slice(start, end);
if (subValue) {
result.push(subValue);
}
start = end;
} while (end < value.length);
selectSNInput.value = result.join('-');
if (selectSNInput.value.length == 19) {
selectConfirmBtn.disabled = false;
} else {
selectConfirmBtn.disabled = true;
}
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<label>Enter a serial number!
<input type="text" value="" class="serial-number">
</label>
<input class="confirm" type="button" value="confirm" disabled><br>
<div class="message"></div>
<script src="js/condition.js"></script>
</body>
</html>

separate elements from google books api

it was a long time ago that I didn’t program in javascript so I decided to make a project of a "bookcase" to manage read books and that I want to read more I have difficulty with how to separate the elements to personalize the style because it selects all the results of the api in one just div.
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="script.js"></script>
<link rel="stylesheet" href="./css/bookcase.css">
<title>project</title>
</head>
<body>
<div id="content">
</div>
<script src="https://www.googleapis.com/books/v1/volumes?q=clean+code&callback=handleResponse></script>
</body>
</html>
js
function handleResponse(response) {
for (var i = 0; i < response.items.length; i++) {
var item = response.items[i];
var book = document.getElementById('content')
book.innerHTML += "<br>" + '<img src=' + response.items[i].volumeInfo.imageLinks.thumbnail + '>';
book..innerHTML += "<br>" + item.volumeInfo.title;
book..innerHTML += "<br>" + item.volumeInfo.authors;
Clean answer - you should use document.appendChild(child) instead of innerHTML method.
Also, there are few recently added js methods that can help you operate large JSON objects - map, reduce, filter.
I added example, how you can clean original object to smaller array, and insert items from that array into html-page.
function demo (obj) {
// getting all items from object
const book = Object.keys(obj).map(item => obj['items']).reduce(
(acc,rec, id, array) => {
// getting Cover, Title, Author from each item
let singleBookCover = rec[id].volumeInfo.imageLinks.thumbnail;
let singleBookTitle = rec[id].volumeInfo.title;
let singleBookAuthor = rec[id].volumeInfo.authors[0];
// Creating new array only with Cover, Title, Author
return [...acc, {singleBookCover, singleBookTitle, singleBookAuthor}]
},
[]
).forEach( item => {
// For each item on our array, we creating h1
let title = document.createElement('h1');
title.textContent = `${item.singleBookTitle} by ${item.singleBookAuthor}`;
// img
let img = document.createElement('img');
img.src = item.singleBookCover;
img.alt = `${item.singleBookTitle} by ${item.singleBookAuthor}`;
// and div wrapper
let container = document.createElement('div');
// adding our child elements to wrapper
container.appendChild(title).appendChild(img);
// adding our wrapper to body
document.body.appendChild(container);
})
return book
}
Hope my answer will help you)
function handleResponse(obj) {
const container = document.getElementById("container")
obj.items.forEach((rec, index) => {
let singleBookCover =
rec.volumeInfo.imageLinks && rec.volumeInfo.imageLinks.smallThumbnail;
let singleBookTitle = rec.volumeInfo.title;
let singleBookAuthor = rec.volumeInfo.authors[0];
let book = document.createElement("div");
book.className = "book"
book.innerHTML = `
<div><h1>${singleBookTitle}<h1>
<p>${singleBookAuthor}</p>
<img src="${singleBookCover}"></img>
</div>
`
content.appendChild(book)
});
}
<div id="content" class="books">
</div>
<script src="https://www.googleapis.com/books/v1/volumes?q=clean+code&callback=handleResponse"></script>

Categories