Javascript ES6: setting <h1> with local storage and form submission - javascript

I am trying to set the element #welcome_banner by using a function in javascript that takes a form submission and sets it to localStorage and then pulls that info and sets it onto an <h1> tag. Apparently it works but only changes the tag for a millisecond and then it disappears! I have tried doing the .innerHTML setting in various places inside and outside of the function clickHandler() and in the main body of the script. I am certain this is something superbasic I am missing.
<!DOCTYPE html>
<html>
<head>
</head>
<script >
//set display name to form submission, set welcome banner to display name
function clickHandler () {
document.querySelector('#display_name').onsubmit = function() {
localStorage.setItem('dn', dn);
document.querySelector('#welcome_banner').innerHTML=changeWelcomeBanner;
}
};
function changeWelcomeBanner () {
var dn = localStorage.getItem('#dn').value;
var welcomeBanner = document.getElementById('#welcome_banner');
welcomBanner.innerHTML = `Hello ${dn}`;
}
</script>
<title>Project 2</title>
<body style="background-color:#ff3300;">
<h1 id="welcome_banner"></h1>
<form id="display_name">
<input id="dn" autocomplete="off" autofocus placeholder="" type="text">
<button>set display name</button>
</body>
</html>

The steps to do this are as follows:
Store the typed text in localStorage, you're doing this in the event handler for the form submission: localStorage.setItem('dn', dn);
When you submit the form, the page is going to refresh from the server. This is why you're only seeing the text briefly, then the page reloads from the server with no knowledge of what was there before.
Look for information about page events and write a handler for the DOMContentLoaded event like you did for your submit event handler. DOMContentLoaded is well supported these days. Something like: document.addEventListener("DOMContentLoaded", function(event) {
// code to check local storage goes here...
});
In that handler you want to check localStorage like you're doing here: var dn = localStorage.getItem('dn').value; and if there is a value there, set the innerHtml of the <h1> to that value, like you're doing here: welcomBanner.innerHTML = 'Hello ${dn}';
I think you might have had a stray # character in your localStorage.getItem call that I removed in the steps above. You might also want to have default text you post if there's nothing found in localStorage when you check.

Here's a simplified example:
If you are calling a function to get the value from Local Storage, be sure you have a return
<!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">
<title>Document</title>
</head>
<body>
<h1 id="welcome"></h1>
<input type="text" id="something">
<button type="button" id="click">CLICK ME</button>
<script>
document.getElementById("click").addEventListener("click", function(){
var x=document.getElementById("something").value;
document.getElementById("welcome").innerHTML=x;
localStorage.setItem('x', JSON.stringify(x));
document.getElementById("welcome").innerHTML = getData();
});
function getData(){
var retrieve=localStorage.getItem('x');
return JSON.parse(retrieve); //Now return the value
}
</script>
</body>
</html>

Related

previous HTML won't render with back button after history.pushState()

I have the below HTML which is served from GET /home and uses Javascript to hijack the form submit event in order to change the method from POST to DELETE. The server listening for requests to DELETE /delete which actually return a 303 redirect to GET /new which serves some HTML. The Javascript updates the address bar to example.com/new using the history API, and renders the HTML using using window.document.documentElement.innerHTML = text. This all works find, and when I click the back button the address bar DOES change back to the previous address (example.com/home) but the HTML is not rendered. Why is this? I've read the Mozilla docs but I can't find anything about not rendering HTML, surely if the back button updates the address bar, the page should be updated to that URL? I also tried using history.replaceState() but it didn't work.
<!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>
<form action="/delete" method="POST">
<input type="submit" value="submit" />
<input name="key" value="val" />
</form>
</body>
<script>
const form = document.querySelector("form");
form.addEventListener("submit", async e => {
e.preventDefault();
console.log(new URLSearchParams(new FormData(e.currentTarget)));
const response = await fetch(form.action, {
body: new URLSearchParams(new FormData(e.currentTarget)),
method: "DELETE",
redirect: "follow",
});
const text = await response.text();
history.pushState({}, "", response.url);
// history.replaceState({}, "", response.url);
window.document.documentElement.innerHTML = text;
});
</script>
</html>
As per your code, you are replacing innerHTML, which includes the script part as well. Please move your script to head tag (if it is possible) or instead replacing innerHTML of the whole document, make a parent div and replace the content of that div.
So instead of this -
window.document.documentElement.innerHTML = text;
Do this -
documemt.getElementById('SomeDIV').innerHTML = text;

JavaScript & HTML: Event Listener Is Not Producing Text Alert As Expected; ReferenceError: button is not defined

I am trying to implement an Event Listener on a DOM (webpage) that produces an alert when a user submits an input inside an input box.
Here is my HTML code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DOM Examples</title>
<!-- <link rel="stylesheet" href="main.css"></link> -->
</head>
<body>
<h1 id="title">This is my Title </h1>
<input type="text" placeholder="some text">
<button id='submit-text-btn'>Submit</button>
<p>
This is the text that is going to display.
I really need to figure out how to balance the next week out.
Maybe just pour myself into this and finish recursion, classes, plus guessing game quickly.
</p>
<script src="dom.js"></script>
</body>
</html>
Here is my JS code:
function getInputAndUpdate(inputElement){
const text = inputElement.value;
inputElement.value = '';
alert(text);
}
button.addEventListener('click', function(){
const inputElement = document.querySelector('input');
getInputAndUpdate(inputElement);
});
Below is a screen shot of my resulting webpage:
My problem is nothing happens when I type text into the input box and click submit. No Alert message pops up at all.
Below is the error I see in the console:
dom.js:10 Uncaught ReferenceError: button is not defined
That's because the button variable you're adding the event listener on hasn't been initialised.
To get a reference of an element in the DOM, use document.getElementById (which retrieves the element that has the ID - note that IDs must be unique), document.getElementsByClassName (which retrieves all elements that have the class) or document.getElementsByTagName (which retrieves all elements by their tag name).
In this case, since you're already using an ID on the button, you can retrieve the element with document.getElementById:
function getInputAndUpdate(inputElement){
const text = inputElement.value;
inputElement.value = '';
alert(text);
}
var button = document.getElementById('submit-text-btn');
button.addEventListener('click', function(){
const inputElement = document.querySelector('input');
getInputAndUpdate(inputElement);
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DOM Examples</title>
<!-- <link rel="stylesheet" href="main.css"></link> -->
</head>
<body>
<h1 id="title">This is my Title </h1>
<input type="text" placeholder="some text">
<button id='submit-text-btn'>Submit</button>
<p>
This is the text that is going to display.
I really need to figure out how to balance the next week out.
Maybe just pour myself into this and finish recursion, classes, plus guessing game quickly.
</p>
<script src="dom.js"></script>
</body>
</html>
Just select your button like this
const button = document.getElementById("submit-text-btn");

Why will fetch only execute when it's not in a function?

I'm just learning Javascript/API call & I'm having trouble with fetch. When I call the fetch function from myFunction it doesn't do anything (that I can see), but if I take it out of myFunction it will display the error message that I expect.
I've tried to Google this but I haven't found anything that has helped me. I've added the console.log statements to make sure that the function is being called, and it is.
I've tried taking the fetch statement out of the function, and instead just putting it as a script in the html file. It works fine then. However I want to call it using the function name of a function that's in a javascript file & I'd like to understand why it's not working correctly right now. I think it has something to do with fetch not returning before the function exits, but I'm not sure.
javascript function:
function myFunction(){
fetch('https://sickw.com/api.php?format=html&key=SOME_KEY&imei=12908438754328705&service=999999')
.then(response => response.text())
.then(data => {
//document.write(data)
console.log(data)
});
//make sure the function was called
console.log("hiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii");
}
html code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Ghibli App</title>
<link href="https://fonts.googleapis.com/css?family=Dosis:400,700" rel="stylesheet" />
<link href="style.css" rel="stylesheet" />
</head>
<body>
<div id="root"></div>
<form>
<select id="carrier">
<option value="carrier">Carrier</option>
<option value="icloud">iCloud</option>
</select>
<button onClick="myFunction('carrier');">Submit</button>"
</form>
<script src="scripts.js"></script>
</body>
</html>
I'm expecting to get a page to come up that says "Error S01: Service ID is wrong!" however the page isn't changing at all when I call the code from myFunction().
Why you don't see anything:
The problem isn't that you're calling fetch from within a function, but that you're calling that function within the onclick of a button in a form.
When you place a <button> element inside of a <form> element, its default behavior is to submit the form (posting the results to a different web page and loading that new page in the browser). Since your form doesn't have an action attribute, it will just reload the current page. This reloading of the current page is causing you to not see any results.
Fixing the first issue:
To prevent the form from returning, you need to call preventDefault() on the event passed to your function:
function myFunction(event){
event.preventDefault();
fetch('https://sickw.com/api.php?format=html&key=SOME_KEY&imei=12908438754328705&service=999999')
.then(response => response.text())
.then(data => {
//document.write(data)
console.log(data)
});
//make sure the function was called
console.log("hiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii");
}
The second issue
However because of the way you're calling this function (passing it to the onclick method of an HTML element) you don't have access to that event. To rectify this, you should use the addEventListener method like so:
document.getElementsByTagName("button")[0].addEventListener("click", myFunction);
If you give the button an ID, this can be replaced with:
document.getElementById("button-id").addEventListener(...)
The third issue
You're passing 'carrier' directly to your function, but my guess is that you want to read the value from the <select> element. To do this, you should use document.getElementById and .value to read the select:
var carrier = document.getElementById("carrier").value;
Once you've done that, you can utilize carrier in your fetch request
The fourth issue
As others have already mentioned in the comments, you should avoid calls to document.write. There are books written about why it's bad, but the proper answer is to use the DOM API to modify elements on the page. For instance:
var p = document.createElement("p");
p.innerHTML = data;
document.appendChild(p);
The final code
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Ghibli App</title>
<link href="https://fonts.googleapis.com/css?family=Dosis:400,700" rel="stylesheet" />
<link href="style.css" rel="stylesheet" />
</head>
<body>
<div id="root"></div>
<form>
<select id="carrier">
<option value="carrier">Carrier</option>
<option value="icloud">iCloud</option>
</select>
<button id="button-id">Submit</button>"
</form>
<script src="scripts.js"></script>
</body>
</html>
script.js
function myFunction(event){
event.preventDefault();
var carrier = document.getElementById("carrier").value;
fetch('https://sickw.com/api.php?format=html&key=SOME_KEY&imei=12908438754328705&service=999999&carrier=' + carrier)
.then(response => response.text())
.then(data => {
var p = document.createElement("p");
p.innerHTML = data;
document.appendChild(p);
});
}
document.getElementById("button-id").addEventListener("click", myFunction);

Use 'window.open' and communicate with a child window

There are two pages in my tomcat server.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button onclick="onBtnClick()">jump to child</button>
<script>
const msg = {
name:'index.html',
ifor:'I am your parent!'
};
function onBtnClick() {
const childWindow = window.open('./child.html');
childWindow.msg = msg
}
</script>
</body>
</html>
child.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="msg-panel"></div>
<script>
const msgPanel = document.querySelector('#msg-panel');
msgPanel.innerHTML = `<span>${msg.name}</span><br><span>${msg.ifor}</span>`
console.log(window.msg);
</script>
</body>
</html>
I want to pass some message( the msg Object in index.html) from index.html to child.html, by the way above.
When I click the button in index.html to open the child.html, sometimes I can get the msg object in child.html, but sometimes I can't.
make the button type="button"
you set the message after opening. Sometimes the computer will be faster and not pass the message before it is shown. Use a timeout to show the message in the child OR
store the message in sessionStorage before calling window.open OR
have the child read the message from the parent:
const msgPanel = document.querySelector('#msg-panel');
msgPanel.innerHTML = `<span>${opener.msg.name}</span><br><span>${opener.msg.ifor}</span>`
console.log(window.msg);
Because you sometimes get that message and sometimes not try to put code from script from index.html in this:
document.addEventListener("DOMContentLoaded", function(event) {
//your code...
}
I think your html is not loaded and you click the button too fast.
Although this is already solved. Another alternative for sending data to a child would be localstorage. Getting and setting is really easy and IE11 is also supported.
localStorage.setItem('msg', 'something important');
let msg = localStorage.getItem('msg');
With that you would also have the ability to send data back and forth by setting event listeners on the localstorage change event like
window.addEventListener('storage', function(e) {
//do some cool stuff here
}
Just in case you want to have a more complex exchange between parent and child.

How can I make a JavaScript function wait for input or value?

As you can see below, I have a function,createCharacter(), that calls another function, getUserInput(). This function is intended to grab the value of a text input element and return that value to be stored in the "name" variable within the createCharacter. However, if you run this code. It completely runs through both functions, never giving the opportunity for the user to input a value. Perhaps a more specific question is, how can I make this function wait for the variable to be defined before returning it to createCharacter? I've tried to wrap the code in a while loop that will run for as long as value is undefined. Didn't work, created an infinite loop and crashed. ANY solution to this problem will be greatly appreciated. I feel like the solution is so simple, but I just can't figure it out for the life of me. Thanks.
var messageDisplay = document.querySelector(".message-display");
var menuInput = document.querySelector(".menu-input");
var playerInput = document.querySelector(".player-text")
function createCharacter() {
messageDisplay.textContent = "Welcome! What is your name?";
var name = getUserInput();
messageDisplay.textContent = "Hello " + name + "!";
}
function getUserInput() {
var textValue = playerInput.value;
return textValue;
}
createCharacter();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="message-display"></div>
<div class="menu-input">
<form class="menu-input-content">
<input class="player-text" type="text">
<input class="submit-button" type="submit">
</form>
</div>
<script type="text/javascript" src="app.js"></script>
</body>
</html>
I think you have a misunderstanding of how the DOM and the user interact. The DOM is event based. You can start by add an change event listener to your input element (or on the submit button):
menuInput.onchange = createCharacter;
And then remove the call to createCharacter, the last line in the code you posted.
This will then call the createCharacter() method when you change the text in the input at all, which is probably not what you want. You could also try:
var menuSubmit = document.querySelector(".submit-button");
menuSubmit.onclick = createCharacter;
And that is probably more on the right track.
However, given your misunderstanding in the first place, perhaps you need to reconsider how you approach your design?
The reason it runs through the code immediately is because of the last line. The browser loads the JS and executes everything in the global scope. Your query selectors are run and stored in those variables, the functions defined, and then on the last line you call one of the defined functions.
To fix this you need to redesign your app to be event based. Keep defining needed variables and functions in the global scope, as you are doing here, but then change your execution to be in response to events.
I think you are looking for something like this. You should be using the events to get what you wanted. You are executing createCharacter() before even the user clicked the Submit button. Hence you see "Hello !" as there is no user input initially.
function submitClicked(event) {
var messageDisplay = document.querySelector(".message-display");
var playerInput = document.querySelector(".player-text");
messageDisplay.innerHTML = "Hello " + playerInput.value;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="message-display"></div>
<div class="menu-input">
<input class="player-text" type="text">
<input class="submit-button" onclick="submitClicked()" type="submit">
</div>
<script type="text/javascript" src="app.js"></script>
</body>
</html>

Categories