Update variable within JavaScript object - javascript

Here's a simplified example of something I'm trying to do.
I've got an input field which I need to get the value from when the user types in his name and click the "Save changes" button.
What I then need is for the username variable to update accordingly to what the user typed in. The page has localization features which complicate things slightly. I can't seem to populate the updated value within the translations object (anywhere username is mentioned, the initialized value is retained and not the last assigned one). This is the part I'm struggling with.
Here's my code:
var p = document.querySelectorAll("p")[0];
var input = document.querySelectorAll("input")[0];
var button = document.querySelectorAll("button")[0];
var locale = "en";
var username = "";
button.onclick = function() {
username = input.value;
document.querySelectorAll("[data-language-key]").forEach(translate);
}
function translate(element) {
const key = element.getAttribute("data-language-key");
const translation = translations[locale][key];
element.innerText = translation;
}
var translations = {
"en": {
"message": `Good morning, ${username}!`,
},
"fr": {
"message": `Bonjour, ${username} !`,
}
}
body {
background-color: gray;
}
button {
margin: 200px;
}
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
</head>
<body>
<p data-language-key="message">Good morning, {username}!</p>
<input type="text" placeholder="Type your name...">
<button>Save changes</button>
</body>
</html>
JavaScript beginner here (if you can ELI5 your answer, I'd appreciate greatly!)

As suggested in the comments, the variable is substituted when the literal is read, therefore we postpone the reading until it's actually needed. This is done using a function.
var p = document.querySelector("p");
var input = document.querySelector("input");
var button = document.querySelector("button");
var locale = "en";
var username = "";
button.onclick = function() {
username = input.value;
translate(document.querySelector("[data-language-key]"));
}
function translate(element) {
var key = element.getAttribute("data-language-key")
const translation = translations[locale][key];
var text = translation(username);
element.innerText = text;
}
var translations = {
"en": {
"message": () => `Good morning, ${username}!`,
},
"fr": {
"message": () => `Bonjour, ${username} !`,
}
}
<p data-language-key="message">Good morning, {username}!</p>
<input type="text" placeholder="Type your name...">
<button>Save changes</button>

Related

Simple temperature converter (javascript, html, try-catch) not working

I'm a complete beginner with coding and I need to write a simple program with javascript and html for an exam, but I need to stick to my professor' standard (hence the specific way this code looks).
I tried to make a simple temperature converter (celsius to fahrenheit) but I don't understand why nothing happens when I click the "convert" button.
EDIT: for some reason the converter works fine here, but when I open it in a new window it doesn't work at all. Any idea why that might be?
function writeText (node, message) {
var nodeText = document.createTextNode(message);
node.replaceChild(nodeText, node.firstChild);
}
function convertHandler () {
try {
if (nodeTemperature.value =="") {
writeText("the field is empty");
return;
}
var temperature = Number(nodeTemperature.value);
if (isNaN(temperature)) {
writeText(nodeTemperature.value + " is not a number");
return;
}
nodeResult.value = temperature * (9/5) + 32;
} catch ( e ) {
alert("convertHandler" + e);
}
}
var nodeTemperature;
var nodeConvert;
var nodeResult;
var ConvertMessage;
function loadHandler () {
try {
nodeTemperature = document.getElementById("temperature");
nodeConvert = document.getElementById("convert");
nodeResult = document.getElementById("result");
nodeConvertMessage = document.getElementById("convertMessage");
nodeTemperature.value = "";
nodeResult.value = "";
nodeConvert.onclick = convertHandler;
var nodeText = document.createTextNode("");
nodeConvertMessage.appendChild(nodeText);
} catch ( e ) {
alert("loadHandler" + e);
}
}
window.onload = loadHandler;
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script scr="p3.js"></script>
<title>Temperature converter</title>
</head>
<body>
<h1>Convert Celsius in Fahrenheit</h1>
<input type="text"
id="temperature"/> Celsius
<br>
<input type ="button"
id="convert"
value="Convert"/>
<span id="convertMessage"></span>
<br>
<input type="text"
id="result"
readonly="readonly"/>Fahrenheit
</body>
</html>
If someone could help me that would save my (academic) life, thank you.

How can I use a dynamic select form to change style in HTML and JavaScript?

I am new just started a course on JS and wanted to have fun on an assignment but perhaps got a little ahead of myself. I decided to do a simple recreation of The Bridge of Death from Monty Python
I am trying to use JS in a HTML file to create a dropdown menu and then when a certain option is selected it changes the color of the paragraph elements.
I am unsure how to pull the values of the options created in the select form to style the element.
What I have now creates the dropdown but the options don't change anything
Sorry if this is super janky, I literally started a week ago.
Here is the code
<!DOCTYPE html>
<html lang="en">
<head>
<title>The Bridge of Death!!!</title>
<meta charset="UTF-8">
</head>
<body>
<h1>You Approach the Bridge of Death</h1>
<button id="q1button" onclick="q1_func()">Talk to Tim </button>
<p id="question_1"></p>
<p id="response_1"></p>
<script>
function q1_func() {
const name = prompt("What is your Name", "Arthur, King of the Britains");
if (name != null) {
document.getElementById("question_1").innerHTML = "What is Your Name?";
document.getElementById("response_1").innerHTML = "My name is " + name;
document.getElementById("q1button").remove();
q2_func();
}
}
</script>
<p id="question_2"></p>
<p id="response_2"></p>
<script>
function q2_func() {
var quest = prompt("What is your Quest", "To seek the Holy Grail!");
if (quest != null) {
document.getElementById("question_2").innerHTML = "What is Your Quest?";
document.getElementById("response_2").innerHTML = quest;
q3_func();
}
}
</script>
<p id="question_3"></p>
<p id="response_3"></p>
<script>
function changeBackground(colors) {
var val = list.options[list.selectedIndex].values;
document.p.style.backgroundColor = val;
}
</script>
<script>
function q3_func() {
var values = [" ", "blue", "red", "pink", "blue...no..."];
var select = document.createElement("select");
select.name = "colors";
select.id = "colors";
select.onchange = "changeBackground(this)";
for (const val of values) {
var option = document.createElement("option");
option.values = val;
option.text = val.charAt(0).toUpperCase() + val.slice(1);
select.appendChild(option);
}
var label = document.createElement("label");
label.innerHTML = "What is you favorite color?";
label.htmlFor = "color";
document.getElementById("question_3").appendChild(label).appendChild(select);
document.getElementById("q2_button").remove();
if (value === "blue...no...") {
alert("Ahhhhh!!!!! *Death* ");
};
}
</script>
</body>
</html>
I feel like there is a better way to create the select form. I could also use html to create it and then hide then reveal it in the q2_func.
Any suggestions on where I could go from here?
Some limitations based on the assignment: no seperate files for js or css, just use js to change the style (no jquery or ajax)
Also the "blue...no..." should lead to an alert but that isn't working either...
Thank you in advance!
-Kevin
Here's your code solution.
If you want to add onchange function you need to use setAttribute function to add onchange function on selectbox in q3_func().
You didn't defined any list veriable in changeBackground function that you want to use in that function event that you're getting colors parameter and you can use colors.options and colors.selectIndex
You can't use document.p directly because p is not defined as veriable or it's not a document but it's a part of document. You can use document.getElementsByTagName('p')[0] [0] indecate index of tags.
For example:
Your are using p tag 5 time in body [0] indecates first p tag and [1] indecates to 2nd.
<!DOCTYPE html>
<html lang="en">
<head>
<title>The Bridge of Death!!!</title>
<meta charset="UTF-8">
</head>
<body>
<h1>You Approach the Bridge of Death</h1>
<button id="q1button" onclick="q1_func()">Talk to Tim </button>
<p id="question_1"></p>
<p id="response_1"></p>
<script>
function q1_func() {
const name = prompt("What is your Name", "Arthur, King of the Britains");
if (name != null) {
document.getElementById("question_1").innerHTML = "What is Your Name?";
document.getElementById("response_1").innerHTML = "My name is " + name;
document.getElementById("q1button").remove();
q2_func();
}
}
</script>
<p id="question_2"></p>
<p id="response_2"></p>
<script>
function q2_func() {
var quest = prompt("What is your Quest", "To seek the Holy Grail!");
if (quest != null) {
document.getElementById("question_2").innerHTML = "What is Your Quest?";
document.getElementById("response_2").innerHTML = quest;
q3_func();
}
}
</script>
<p id="question_3"></p>
<p id="response_3"></p>
<script>
function changeBackground(colors) {
var val = colors.options[colors.selectedIndex].values;
document.getElementsByTagName('p')[0].style.backgroundColor = val;
}
</script>
<script>
function q3_func() {
var values = [" ", "blue", "red", "pink", "blue...no..."];
var select = document.createElement("select");
select.name = "colors";
select.id = "colors";
select.setAttribute("onchange", "changeBackground(this)");
for (const val of values) {
var option = document.createElement("option");
option.values = val;
option.text = val.charAt(0).toUpperCase() + val.slice(1);
select.appendChild(option);
}
var label = document.createElement("label");
label.innerHTML = "What is you favorite color?";
label.htmlFor = "color";
document.getElementById("question_3").appendChild(label).appendChild(select);
document.getElementById("q2_button").remove();
if (value === "blue...no...") {
alert("Ahhhhh!!!!! *Death* ");
};
}
</script>
</body>
</html>
I hope you understand this.
I figured out the alert trigger!
Using the changes Abdul made I added the following code to the end of the changeBackground function:
var x = document.getElementById("colors").selectedIndex;
var y = document.getElementById("colors").options;
if (y[x].index === 4){
alert("Ahhhhgggg!!! .... *Death*");
};
It works completely now.
Thank you
Kevin

Adding and removing form via js not working

I am a newbie trying to learn JavaScripts. So I'm trying to clone an app called Momentum, and I am facing a problem with adding and removing the form and name of the user.
as it can be seen in the loadName() function, if there is a name, it should activate greetUser() function to remove the "showing" class from the form and add the "showing" to greeting class list. If there isn't a name, it should display a form where the user can enter their name.
However, even if I assign the name or not, neither the form will display nor the name.
I have tried changing the names, css file, and other things that I could think of but did not work as I expected. Below is the code that I am working with. It probably is some stupid mistake that I've made, but I just am not able to find out what the problem is.
greetings.js
const form = document.querySelector(".js-form");
const input = form.querySelector("input");
const greeting = document.querySelector(".js-greetings");
const USER_LS = "currentUser";
const SHOWING_CN = "showing";
function saveName(text) {
localStorage.setItem(USER_LS, text);
}
function handleSubmit() {
event.preventDefault();
const currentValue = input.value;
greetUser(currentValue);
saveName(currentValue);
}
function askForName() {
form.classList.add(SHOWING_CN);
form.addEventListener("submit", handleSubmit);
}
function greetUser(text) {
form.classList.remove(SHOWING_CN);
greeting.classList.add(SHOWING_CN);
greeting.innerText = `Hello, ${text}`;
}
function loadName() {
const currentUser = localStorage.getItem(USER_LS);
if (currentUser === null) {
askForName();
} else {
greetUser(currentUser);
}
}
function init() {
loadName();
}
index.css
.form,
.greetings {
display: none;
}
.showing {
display: block;
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Something</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="js-clock">
<h1>00:00</h1>
</div>
<form class="js-form form">
<input type="text" placeholder="What is your name?" />
</form>
<h4 class="js-greetings greetings"></h4>
<script src="clock.js"></script>
<script src="greetings.js"></script>
</body>
</html>
There was an issue with firing off your loadName() function. This was being called from init(), but nothing was calling init(). I changed it to call loadName() once the window has loaded. There was also an issue with getting the constant USER_LS from local storage when it hadn't yet been set. I've just referred directly to it since it is defined globally. I've demonstrated the USER_LS being set to a name as well as to null (this is commented out since a constant can only be defined once) to show how the inputs appear for each scenario:
const form = document.querySelector(".js-form");
const input = form.querySelector("input");
const greeting = document.querySelector(".js-greetings");
// const USER_LS = null;
const USER_LS = "Bob";
const SHOWING_CN = "showing";
function saveName(text) {
localStorage.setItem(USER_LS, text);
}
function handleSubmit() {
event.preventDefault();
const currentValue = input.value;
greetUser(currentValue);
saveName(currentValue);
}
function askForName() {
form.classList.add(SHOWING_CN);
form.addEventListener("submit", handleSubmit);
}
function greetUser(text) {
form.classList.remove(SHOWING_CN);
greeting.classList.add(SHOWING_CN);
greeting.innerText = `Hello, ${text}`;
}
function loadName() {
const currentUser = USER_LS;
if (currentUser === null) {
askForName();
} else {
greetUser(currentUser);
}
}
window.load = loadName();
.form,
.greetings {
display: none;
}
.showing {
display: block;
}
<div class="js-clock">
<h1>00:00</h1>
</div>
<form class="js-form form">
<input type="text" placeholder="What is your name?" />
</form>
<h4 class="js-greetings greetings"></h4>
<script src="clock.js"></script>
<script src="greetings.js"></script>

Unable to access object property of state object in state modification method (TypeError)

I'm working on a text analyzer in jQuery that returns word count, unique word count, average word length, and average sentence length.
I had it working (at least halfway, up to the unique word count functionality) before I realized my structure was horrible. So I refactored it...and now I'm having trouble getting it to work at all.
On line 65, I'm getting TypeError: Cannot read property 'length' of null. This is in reference to state.sentences, which when I console.log, I get null. I just noticed that when I type in a full sentence as my input, that doesn't come up (and it logs the sentence correctly), but it's still not rendering the content to the DOM.
What am I doing wrong here? Something about the way I'm trying to access the state object, obviously -- but what, exactly, is beyond me.
Here is the index.js:
'use strict'
// state object
var state = {
text: "",
words: [],
uniqueWords: [],
sentences: [],
wordLengths: [],
sentenceLengths: [],
wordCount: 0,
uniqueWordCount: 0,
averageWordLength: 0,
averageSentenceLength: 0
}
//state modification functions
var getText = function(state) {
state.text = $('#user-text').val()
}
var getWords = function(state) {
state.words = state.text.match(/[^_\W]+/g)
//need to also change all uppercase to lowercase
}
var getSentences = function(state) {
state.sentences = state.text.match( /[^\.!\?]+[\.!\?]+/g )
}
var getUniqueWords = function(state) {
for (var i = 0; i < state.words.length; i++) {
if (state.uniqueWords.indexOf(state.words[i]) < 0) {
state.uniqueWords.push(state.words[i])
}
}
}
var getWordCount = function(state) {
state.wordCount = state.words.length
}
var getUniqueWordCount = function(state) {
state.uniqueWordCount = state.uniqueWords.length
}
var getWordLengths = function(state) {
for (var i = 0; i < state.words.length; i++) {
state.wordLengths.push(state.words[i].length)
console.log(state.wordLengths)
}
}
var getAverageWordLength = function(state) {
var sum = state.wordLengths.reduce(function(a, b) {
return a + b
}, 0)
state.averageWordLength = sum/state.wordLengths.length
}
var getSentenceLengths = function(state) {
for (var i = 0; i < state.sentences.length; i++) {
state.sentenceLengths.push(state.sentences[i].length)
}
}
var getAverageSentenceLength = function(state) {
var sum = state.sentenceLengths.reduce(function(a,b) {
return a + b
}, 0)
state.averageSentenceLength = sum/state.sentenceLengths.length
}
// render functions
var renderWordCount = function(state, element) {
$("dl").toggleClass('hidden')
return element.append(state.wordCount)
}
var renderUniqueWordCount = function(state, element) {
$("dl").toggleClass('hidden')
return element.append(state.uniqueWordCount)
}
var renderAverageWordLength = function(state, element) {
$("dl").toggleClass('hidden')
return element.append(state.averageWordLength)
}
var renderAverageSentenceLength = function(state, element) {
$("dl").toggleClass('hidden')
return element.append(state.averageSentenceLength)
}
// event listener functions
$(function() {
$('button').click(function() {
event.preventDefault()
getText(state)
getWords(state)
getSentences(state)
getUniqueWords(state)
getWordCount(state)
getUniqueWordCount(state)
getAverageWordLength(state)
getSentenceLengths(state)
getAverageSentenceLength(state)
renderWordCount(state, $('.wordCount'))
renderUniqueWordCount(state, $('.uniqueWordCount'))
renderAverageWordLength(state, $('.averageWordLength'))
renderAverageSentenceLength(state, $('.averageSentenceLength'))
})
})
And here is the index.html:
<!DOCTYPE html>
<html>
<head>
<title>Text analyzer</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/4.2.0/normalize.min.css">
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<div class="container">
<main>
<h1>Text analzyer</h1>
<p>Paste in text below, submit, and get some basic stats back.</p>
<form class="js-form">
<div>
<label for="user-text">Text to analyze</label>
<textarea cols="60" rows="20" id="user-text" name="user-text" placeholder="What have you got to say?" required></textarea>
</div>
<div>
<button type="submit">Analyze it!</button>
</div>
</form>
<dl class="hidden text-report">
<dt>Word count</dt>
<dd class="wordCount"></dd>
<dt>Unique word count</dt>
<dd class="uniqueWordCount"></dd>
<dt>Average word length</dt>
<dd class="averageWordLength"></dd>
<dt>Average sentence length</dt>
<dd class="averageSentenceLength"></dd>
</dl>
</main>
</div>
<script src="jquery-3.1.1.js"></script>
<!-- <script src="app.js"></script> -->
<script src="index.js"></script>
</body>
</html>
Thank you!
P.S. If you have any ideas about structuring the app, all thoughts are welcome; I especially am concerned about the way I'm calling all the functions one after another in the ready function at the end. That seems kinda messy for some reason.
Your problem lies in here:
$(function() {
$('button').click(function() {
event.preventDefault()
getText(state) // <---at this point you are passing an object to set the text in.
// state object but getText has some-thing which is not correct
//.....other too
})
})
var getText = function(state) {
state.text = $('user-text').val() // <-----Here `user-text` is not a valid
// html element and jquery doesn't recognize it.
// So, You should change it to a valid css selector.
}
So, eventually you should use a Id selector:
$('#user-text').val()
As your html element has Id attribute:
<textarea cols="60" rows="20"
id="user-text"
name="user-text"
placeholder="What have you got to say?" required></textarea>

How to store and re-use text input values and variable values that use Math.random()?

Okay, so I'm trying to create a quiz application for revision purposes that asks a random question from a list of questions, takes a text input as the users answer to the question, and then compares it to the actual answer to the question. The code I have used is:
var keyList = Object.keys(htmlModule);
var ranPropName = keyList[ Math.floor(Math.random()*keyList.length) ];
var pageStart = function() {
document.getElementById("question").innerHTML = htmlModule[ranPropName][0];
document.getElementById("submit").onclick = answerValidation;
};
window.onload = pageStart;
var answerValidation = function(correctAnswer, userAnswer) {
correctAnswer = htmlModule[ranPropName][1];
userAnswer = document.getElementById("submit").value;;
if(userAnswer === correctAnswer) {
document.getElementById("rightWrong").style.backgroundColor = "green";
} else {
document.getElementById("rightWrong").style.backgroundColor = "red";
}
};
The variable htmlModule refers to the object in which the questions and their answers are stored. Each question and answer pair is stored inside an array that is the value of its property, the property simply being a key used to reference each pair e.g. htmlQ1, htmlQ2 etc.
The main problem I seem to be having is that my if statement comparing the actual answer and the user answer won't evaluate to true. I know this because the background colour of the div element rightWrong only ever turns red, even when I've definitely typed in a correct answer at which point it should turn green. My assumption is that either the text input isn't being stored for some reason, or the value of the variable ranPropName that uses Math.random() is changing due to the use of Math.method(), but I'm stuck as to how to remedy either potential problem. Thanks in advance for any replies.
Well, I started to visualize your quiz as you explained.
One thing is need to be changed is that you get userAnswer from the value of an element with Id submit which I assume most probably it's an button tag, so I write a working code sample as follow:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Title Goes Here</title>
</head>
<body>
<input type="text" id="rightWrong" />
<div id="question" />
<button id="submit">Submit</button>
</body>
<script>
var htmlModule = {
'htmlQ1': ['1+1=?', '2'],
'htmlQ2': ['2+2=?', '4']
};
var keyList = Object.keys(htmlModule);
var ranPropName = keyList[ Math.floor(Math.random()*keyList.length) ];
var pageStart = function() {
document.getElementById("question").innerHTML = htmlModule[ranPropName][0];
document.getElementById("submit").onclick = answerValidation;
};
window.onload = pageStart;
var answerValidation = function(correctAnswer, userAnswer) {
correctAnswer = htmlModule[ranPropName][1];
userAnswer = document.getElementById("rightWrong").value;
if(userAnswer === correctAnswer) {
document.getElementById("rightWrong").style.backgroundColor = "green";
} else {
document.getElementById("rightWrong").style.backgroundColor = "red";
}
};
</script>
</html>
Please share your html if you still face problems.

Categories

Resources