Trying to hide notice for 30 days with the following - javascript

I'm trying to hide a notification bar I built after a user clicks x on the following codepen for 30 days based on cookies. I can't seem to figure out how to do this. https://codepen.io/Danskii/pen/aWpoRP
HTML:
<div id="top-site-message-wrapper">
<div id="top-site-message">
Members: you can reduce paper consumption by choosing to receive your membership package by email:
<a href="http://www.oct.ca/" id="top-site-message-CTA">
Yes Please</a>
<button id="top-site-message-hide">
x
</button>
</div>
</div>
CSS:
#top-site-message-wrapper {
background-color: #068edb;
padding: 30px 13px 30px 30px;
border-radius: 3px;
max-width: 100%;
font-size: 16px;
font-style: normal;
font-weight: 600
}
#top-site-message {
color: white;
text-align: center;
}
#top-site-message-CTA {
width: 10%;
color: white;
text-decoration: none;
background: #043d86;
padding: 10px;
border-radius: 3px;
}
#top-site-message-hide {
float: right;
border: none;
color: white;
background-color: blue;
border-radius: 3px;
}
div.yay {
display: none;
}
button.yay {display: none;
}
JS:
// Selects the FIRST occurance of <button>;
var button = document.querySelector("button");
var element = document.querySelector("div");
button.addEventListener("click", function() {
element.classList.toggle("yay");
button.classList.toggle("yay");
});
// Begin script portion for cookies
function TopMessage(){
days=30;
myDate = new Date();
myDate.setTime(myDate.getTime()+(days*24*60*60*1000));
document.cookie = 'TopMessage=Hidden; expires=' + myDate.toGMTString();
}
var cookie = document.cookie.split(';')
.map(function(x){ return x.trim().split('='); })
.filter(function(x){ return x[0]==='TopMessage'; })
.pop();
if(cookie && cookie[1]==='Accepted') {
$("div.yay").hide();
$("button.yay").hide();
}
$('.top-site-message-hide').on('click', function(){
TopMessage();
return false;
});

Related

First time deploying Chrome extension - Uncaught TypeError: Cannot read properties of null (reading 'length')

I am trying to deploy my first javascript application, which is a Chrome extension.
This simply generates random passwords and stores it with the url of current active tab.
App runs fine on local but after deploying it to Chrome, I got this error:
Uncaught TypeError: Cannot read properties of null (reading 'length')
index.js:65 (anonymous function)
I am a beginner, so any kind of criticism about my code is highly appreciated.
Thank you so much.
function render() {
*line65* **if(passwords.length === 0)** {
document.getElementById("saved-passwords-container").style.display= "none";
} else {
document.getElementById("saved-passwords-container").style.display= "unset";
}
let list = ""
**for (let i = 0; i < passwords.length; i++)** {
list += `<div class="saved-password-line"><span>${passwords[i]}</span></br></br><span class="link"><a target='_blank'href='${links[i]}'>${links[i]}</a></span></div>`
}
document.getElementById("passwords-el").innerHTML = list
}
Here is the full index.js file:
var characters = [];
for (var i=32; i<127; i++)
characters.push(String.fromCharCode(i));
for( var i = 0; i < characters.length; i++){
if ( characters[i] === '<') {
characters.splice(i, 1);
i--;
}
}
for( var i = 0; i < characters.length; i++){
if ( characters[i] === '>') {
characters.splice(i, 1);
i--;
}
}
let pw1El = document.getElementById("pw1-el")
let pw1 = ""
let passwords = []
passwords = JSON.parse(localStorage.getItem("savedPasswords"))
let links = []
links = JSON.parse(localStorage.getItem("savedLinks"))
render()
document.getElementById("char-count-el").value = 20
document.getElementById("gen-btn").addEventListener("click", function() {
var charCount = document.getElementById("char-count-el").value
pw1 = ""
for(let i = 0; i < charCount; i++) {
let randomIndex = Math.floor(Math.random() * characters.length)
pw1 += (characters[randomIndex])
}
pw1El.textContent = pw1
})
document.getElementById("save-btn").addEventListener("click", function() {
passwords.push(pw1El.innerText)
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
links.push(tabs[0].url)
})
localStorage.setItem("savedPasswords", JSON.stringify(passwords))
localStorage.setItem("savedLinks", JSON.stringify(links))
render()
})
function render() {
**if(passwords.length === 0)** {
document.getElementById("saved-passwords-container").style.display= "none";
} else {
document.getElementById("saved-passwords-container").style.display= "unset";
}
let list = ""
**for (let i = 0; i < passwords.length; i++)** {
list += `<div class="saved-password-line"><span>${passwords[i]}</span></br></br><span class="link"><a target='_blank'href='${links[i]}'>${links[i]}</a></span></div>`
}
document.getElementById("passwords-el").innerHTML = list
}
document.getElementById("clear-btn").addEventListener("click", function() {
passwords = []
links = []
localStorage.setItem("savedPasswords", JSON.stringify(passwords))
localStorage.setItem("savedLinks", JSON.stringify(links))
render()
})
document.getElementById("copy-btn").addEventListener("click", function() {
var input = document.getElementById("pw1-el").textContent;
navigator.clipboard.writeText(input);
alert("Copied Text: " + input);
})
index.html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div class="container">
<h1>Generate a</br>random password</h1>
<p>Never use an unsecure password again.</p>
<hr>
<div>
<label for="char-count-el">Character Count:</label>
<input type="number" id="char-count-el">
<button id="gen-btn"><span>Generate password</span></button>
</div>
<div>
<label>Your Password:</label>
<div class="pw-container">
<span class="password-line" id="pw1-el">...</span>
<button class="side-btn" id="save-btn">SAVE</button>
<button class="side-btn" id="copy-btn">COPY</button>
</div>
</div>
<div id="saved-passwords-container">
<hr>
<label>Saved Passwords:</label>
<div class="pw-container">
<div id="passwords-el">...</div>
<button class="side-btn" id="clear-btn">CLEAR</button>
</div>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
index.css
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
background-color: #ffffff;
color: white;
display: flex;
justify-content: center;
align-items: center;
}
h1::first-line {
color: white;
}
h1 {
color: #00ffaa;
margin-bottom: 5px;
line-height: 1;
}
label {
font-size: 11px;
display: block;
color: #D5D4D8;
margin-top: 10px;
}
input {
height: 38px;
border-radius: 5px;
border: none;
width: 70px;
padding: 0px 10px;
text-align: center;
background-color: #D5D4D8;
margin-right: 20px;
font-size: 14px;
}
.container {
background: #1F2937;
margin: 0;
padding: 10px 30px 40px;
width: 100%;
min-width: 500px;
box-shadow: 0px 10px 30px 10px #2640644b;
display: flex;
flex-direction: column;
}
.pw-container {
display: flex;
border-radius: 5px;
background-color: #3e4f66;
padding: 10px;
margin-top: 10px;
}
.password-line {
color: #00ffaa;
font-size: 16px;
padding: 5px 10px;
margin-top: 0px;
flex-grow: 1;
flex: 1 1 1;
min-width: 0;
word-wrap: break-word;
white-space: pre-wrap;
word-break: break-word;
}
#passwords-el {
padding-right: 30px;
flex-grow: 1;
flex: 1 1 0;
min-width: 0;
word-wrap: break-word;
white-space: pre-wrap;
word-break: break-word;
}
.saved-password-line {
color: #D5D4D8;
font-size: 14px;
padding: 10px 15px;
border-bottom: solid 1px #d5d4d814;
border-radius: 5px;
margin-bottom: 10px;
line-height: 0.9;
}
a {
color: #d5d4d872;
text-decoration: underline;
}
.side-btn {
font-size: 12px;
width: 60px;
border: none;
background: none;
color: #D5D4D8;
padding: 5px 10px;
border-radius: 5px;
justify-self: flex-end;
}
.side-btn:hover {
background-color: #ffffff28 ;
}
#gen-btn {
color: #ffffff;
background: #0EBA80;
text-transform: capitalize;
text-align: center;
width: 200px;
height: 40px;
padding: 10px 10px;
border: none;
border-radius: 5px;
margin-bottom: 10px;
margin-top: 10px;
transition: all 0.5s;
box-shadow: 0px 0px 30px 5px #0eba8135
}
#gen-btn:hover {
box-shadow: 0px 0px 30px 10px #0eba8157
}
#gen-btn span {
cursor: pointer;
display: inline-block;
position: relative;
transition: 0.5s;
}
#gen-btn span:after {
content: '\279c';
position: absolute;
opacity: 0;
top: 0;
right: -20px;
transition: 0.5s;
}
#gen-btn:hover span {
padding-right: 25px;
}
#gen-btn:hover span:after {
opacity: 1;
right: 0;
}
p {
color: #D5D4D8;
margin-top: 0px;
}
hr {
border-width: 1px 0px 0px 0px;
border-color: #95959576;
margin: 15px 0;
}
manifest.json
{
"manifest_version": 3,
"version": "1.0",
"name": "Password Generator",
"action": {
"default_popup": "index.html",
"default_icon": "icon.png"
},
"permissions": [
"tabs"
]
}
I solved it.
I understand that (please correct me if I'm wrong)
if the local storage is empty, it does not return an empty array when parsed.
Apparently, when I do:
passwords = JSON.parse(localStorage.getItem("savedPasswords"))
passwords is no longer an array.
I instead use:
passwords.push(JSON.parse(localStorage.getItem("savedPasswords")))
But that just pushes a nested array inside passwords.
So I added a for loop, and used an if statement to address the initial error:
let locSavedPasswords = localStorage.getItem("savedPasswords")
if(locSavedPasswords !== null) {
for( var i = 0; i < (JSON.parse(locSavedPasswords)).length; i++){
passwords.push(JSON.parse(locSavedPasswords)[i])
}}
Initially, savedPasswords won't exist in localStorage, so localStorage.getItem('savedPasswords') will return null.
You then do JSON.parse(null), which doesn't immediately crash because null is first coerced to a string and becomes 'null' which is then JSON-parsed and turns back to null since the string with contents null is valid JSON.
But you then do .length on it and crash.
The solution is to handle the case where the item is not yet set and handle it like it was a JSON-stringified empty array. You can do so for example using the nullish coalescing operator ??:
let passwords = JSON.parse(localStorage.getItem("savedPasswords") ?? '[]')
Or, you can keep initializing it with [] as you did before but wrap the assignment with the actual value in a condition:
let passwords = []
const json = localStorage.getItem('savedPasswords')
if (json !== null) {
passwords = JSON.parse(json)
}
Personally, what I like to do for structured data in localStorage is something like this, which also handles the case that other things like invalid JSON somehow got stored there (without bricking the application):
let passwords = []
try {
const data = JSON.parse(localStorage.getItem('savedPasswords'))
if (Array.isArray(data)) passwords = data
} catch {}

Javascript Blur background when div is block?

I'm having a problem with bluring the background when my menu is open. I tried writing something on my own but it's not working.
function backgroundBlur() {
var menuBox = document.getElementById("mobile-menu");
var blur = document.getElementById("body");
if (menuBox.style.dsiplay = "block") {
blur.style.filter = "blur(3px)";
}
}
I think the problem can be caused by three reasons:
Typo noted by #RyanWalls
The backgroundBlur() method is not called
The display property of the menuBox is not block
I made a run to simulate this event:
let button = document.getElementById('setBlur');
let control = false;
function backgroundBlur(control) {
var menuBox = document.getElementById("mobile-menu");
var blur = document.getElementById("body");
if (menuBox.style.display === "block")
{
if(!control)
{
blur.style.filter = "blur(3px)";
button.innerHTML = 'Remove Blur';
}
else
{
blur.style.filter = "blur(0px)";
button.innerHTML = 'Add Blur';
}
}
}
button.addEventListener('click', function() {
backgroundBlur(control);
control = !control;
});
*{
margin: 0;
}
#body{
background-color: black;
}
button{
margin-top: 25px;
background-color: #4CAF50;
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
width: 100%;
}
.vertical-menu {
width: 200px;
}
.vertical-menu a {
background-color: #eee;
color: black;
display: block;
padding: 12px;
text-decoration: none;
}
.vertical-menu a:hover {
background-color: #ccc;
}
.vertical-menu a.active {
background-color: #04AA6D;
color: white;
}
<div id="body">
<div id="mobile-menu" style="display: block;">
<div class="vertical-menu">
Home
Link 1
</div>
</div>
</div>
<button id="setBlur">Add Blur</button>

How to control the span characteristics based on given data

The following HTML code creates 3 elements, and allows the user to click on them / select them.
const changeColor = (evt) => {
if (evt.currentTarget.classList.contains("is-active")) {
evt.currentTarget.classList.remove("is-active");
} else {
evt.currentTarget.classList.add("is-active");
}
};
const EL_tagger1010_children = document.querySelectorAll(".tagger1010 span");
EL_tagger1010_children.forEach(EL => EL.addEventListener("click", changeColor));
.tagger1010 span {
padding: 6px 10px;
background: #D0E8E4;
border-radius: 18px;
color: #000000;
font-family: Roboto;
font-size: 12px;
margin: 0 4px 8px 0;
font-weight: 500;
display: inline-block;
word-wrap: break-word;
white-space: normal;
cursor: pointer;
user-select: none;
border: 1px solid BBD0CD;
}
.tagger1010 span.is-active {
background-color: #008fde;
color: #ffffff;
}
.tagger1010 span:hover {
background-color: #008fde;
color: #ffffff;
}
<div class="tagger1010">
<span>Google</span>
<span>Microsoft</span>
<span>Facebook</span>
<span>LinkedIn</span>
</div>
<div class="as-console-wrapper"></div>
<div class="as-console"></div>
What I am looking to do is pre-assign spans as "is-active" if the tag is included in a given list.
For example, if you run the above code, and the given list includes "Microsoft" and "LinkedIn" - I would like for "Microsoft" and "LinkedIn" to already be highlighted and have the background-color be #008fde, and the color be #ffffff.
Would anyone know how I could say, "if the text of this span is included in this list, make it have the is-active characteristics"
Checkout here
https://jsfiddle.net/qmx3105s/
<script type="text/javascript">
const changeColor = (evt) => {
if (evt.currentTarget.classList.contains("is-active")){
evt.currentTarget.classList.remove("is-active");
localStorage.removeItem(evt.currentTarget.textContent);
} else {
evt.currentTarget.classList.add("is-active");
localStorage.setItem(evt.currentTarget.textContent,'true');
}
};
const EL_tagger1010_children = document.querySelectorAll(".tagger1010 span");
EL_tagger1010_children.forEach(EL => {
console.log('EL',EL)
if(localStorage.getItem(EL.textContent)){
EL.classList.add("is-active");
}
EL.addEventListener("click", changeColor);
});
</script>
Edited: Search by innerText and Find in Array added.
Original: I highly recommend adding id="X" to your html to make it easier to target the specific tag. Having to rely on the inner text is much more complicated and bad practice.
Then you need an array to hold your IDs and iterate it. Finally we add the .is-active
Here's what that looks like:
const changeColor = (evt) => {
if (evt.currentTarget.classList.contains("is-active")) {
evt.currentTarget.classList.remove("is-active");
} else {
evt.currentTarget.classList.add("is-active");
}
};
const EL_tagger1010_children = document.querySelectorAll(".tagger1010 span");
EL_tagger1010_children.forEach(EL => EL.addEventListener("click", changeColor));
var tag_names = ["Microsoft", "LinkedIn"];
var tags = document.getElementsByTagName("span");
for (var i = 0; i < tags.length; i++) {
if(tag_names.indexOf( tags[i].textContent ) != -1){
tags[i].classList.add('is-active');
}
}
.tagger1010 span {
padding: 6px 10px;
background: #D0E8E4;
border-radius: 18px;
color: #000000;
font-family: Roboto;
font-size: 12px;
margin: 0 4px 8px 0;
font-weight: 500;
display: inline-block;
word-wrap: break-word;
white-space: normal;
cursor: pointer;
user-select: none;
border: 1px solid BBD0CD;
}
.tagger1010 span.is-active {
background-color: #008fde;
color: #ffffff;
}
.tagger1010 span:hover {
background-color: #008fde;
color: #ffffff;
}
<div class="tagger1010">
<span>Google</span>
<span>Microsoft</span>
<span>Facebook</span>
<span>LinkedIn</span>
</div>
<div class="as-console-wrapper"></div>
<div class="as-console"></div>

A Notepad that keep the notes written even after refresh

I have just found a set of codes that fits my need right now for my blog.
Here I'll attach the code and a glimpse of what it looks like. Although It's still very simple.
What I want to ask is if it's possible to tweak these code possible using JS localstorage, so that it will keep all the saved text even after the user refresh the page, or even better if it stays there even after a user closed the window and reopened it later?
Here's what it looks like right now
and here is the code:
$(document).ready(function(){
var noteCount = 0;
var activeNote = null;
$('.color-box').click(function(){
var color = $(this).css('background-color');
$('notepad').css('background-color', color);
$('#title-field').css('background-color', color);
$('#body-field').css('background-color', color);
})
$('#btn-save').click(function(){
var title = $('#title-field').val();
var body = $('#body-field').val();
if (title === '' && body === '') {
alert ('Please add a title or body to your note.');
return;
}
var created = new Date();
var color = $('notepad').css('background-color');
var id = noteCount + 1;
if (activeNote) {
$('#' + activeNote)[0].children[0].innerHTML = title;
$('#' + activeNote)[0].children[1].innerHTML = created.toLocaleString("en-US");
$('#' + activeNote)[0].children[2].innerHTML = body;
$('#' + activeNote)[0].style.backgroundColor = color;
activeNote = null;
$('#edit-mode').removeClass('display').addClass('no-display');
} else {
var created = new Date();
$('#listed').append('<div id="note' + id + '" style="background-color: ' + color + '"><div class="list-title">' + title + '</div> <div class="list-date">' + created.toLocaleString("en-US") + '</div> <div class="list-text">' + body + '</div> </div>');
noteCount++;
};
$('#title-field').val('');
$('#body-field').val('');
$('notepad').css('background-color', 'white');
$('#title-field').css('background-color', 'white');
$('#body-field').css('background-color', 'white');
});
$('#btn-delete').click(function(){
if (activeNote) {
$('#' + activeNote)[0].remove();
activeNote = null;
$('#edit-mode').removeClass('display').addClass('no-display');
}
$('#title-field').val('');
$('#body-field').val('');
$('notepad').css('background-color', 'white');
$('#title-field').css('background-color', 'white');
$('#body-field').css('background-color', 'white');
});
$('#listed').click(function(e){
var id = e.target.parentElement.id;
var color = e.target.parentElement.style.backgroundColor;
activeNote = id;
$('#edit-mode').removeClass('no-display').addClass('display');
var titleSel = $('#' + id)[0].children[0].innerHTML;
var bodySel = $('#' + id)[0].children[2].innerHTML;
$('#title-field').val(titleSel);
$('#body-field').val(bodySel);
$('notepad').css('background-color', color);
$('#title-field').css('background-color', color);
$('#body-field').css('background-color', color);
})
})
header {
text-align: left;
font-weight: 800;
font-size: 28px;
border-bottom: solid 3px #DEDEDE;
display: flex;
justify-content: space-between;
}
footer {
display: flex;
flex-flow: row-reverse;
padding: 5px 20px;
}
.headers {
margin-top: 20px;
margin-bottom: -10px;
font-size: 20px;
}
#list-head {
margin-left: 2.5%;
width: 30.5%;
display: inline-block;
text-align: center;
}
#note-head {
width: 60%;
margin-left: 5%;
display: inline-block;
text-align: center;
}
noteList {
margin-top: 20px;
display: inline-block;
margin-left: 2.5%;
width: 30.5%;
height: 400px;
overflow: scroll;
border: solid 3px #929292;
border-radius: 5px;
background-color: #DEDEDE;
}
.within-list {
cursor: pointer;
}
.list-title {
font-weight: 600;
font-size: 20px;
padding: 5px 5px 0 5px;
}
.list-date {
font-weight: 200;
font-style: italic;
font-size: 12px;
padding: 0 5px 0 5px;
}
.list-text {
padding: 0 5px 5px 5px;
border-bottom: solid 1px black;
}
notePad {
display: inline-block;
border: solid 3px black;
border-radius: 10px;
height: 400px;
overflow: scroll;
width: 60%;
margin-left: 5%;
margin-top: 0;
}
#note-title {
font-size: 24px;
padding: 0 0 5px 5px;
border-bottom: solid 2px #DEDEDE;
}
#note-body {
padding: 5px;
}
#body-field, #title-field {
width: 100%;
border: none;
outline: none;
resize: none;
}
#title-field {
font-size: 18px;
font-weight: 600;
}
#body-field {
font-size: 14px;
font-weight: 500;
height: 400px;
}
#color-select {
display: flex;
flex-flow: row-reverse nowrap;
padding: 5px 10px 0 0;
}
.color-box {
border: solid 2px #929292;
height: 10px;
width: 10px;
margin-left: 5px;
}
.display {
display: visible;
}
.no-display {
display: none;
}
button {
margin: 5px;
border: solid 3px grey;
border-radius: 10%;
font-size: 22px;
font-weight: 800;
text-transform: uppercase;
color: #DEDEDE;
}
button:hover, .color-box:hover {
cursor: pointer;
}
#listed:nth-child(odd):hover {
cursor: pointer;
}
#btn-save {
background-color: #2F5032;
}
#btn-delete {
background-color: #E41A36;
}
.white {
background-color: white;
}
.orange {
background-color: #FFD37F;
}
.banana {
background-color: #FFFA81;
}
.honeydew {
background-color: #D5FA80;
}
.flora {
background-color: #78F87F;
}
.aqua {
background-color: #79FBD6;
}
.ice {
background-color: #79FDFE;
}
.sky {
background-color: #7AD6FD;
}
.orchid {
background-color: #7B84FC;
}
.lavendar {
background-color: #D687FC;
}
.pink {
background-color: #FF89FD;
}
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title></title>
<link rel='stylesheet' href='style.css'>
</head>
<body>
<header>
The Note Machine
<div id='color-select'>
<div class='color-box white'></div>
<div class='color-box orange'></div>
<div class='color-box banana'></div>
<div class='color-box honeydew'></div>
<div class='color-box flora'></div>
<div class='color-box aqua'></div>
<div class='color-box ice'></div>
<div class='color-box sky'></div>
<div class='color-box orchid'></div>
<div class='color-box lavendar'></div>
<div class='color-box pink'></div>
</div>
</header>
<main>
<div class="headers">
<div id="list-head">
<b>Your Notes</b> <i>(click to edit/delete)</i>
</div>
<div id="note-head">
<b>Your Notepad</b>
<span id="edit-mode" class="no-display">
<i> (edit mode) </i>
</span>
</div>
</div>
<noteList>
<div id='listed'>
</div>
</noteList>
<notepad>
<div id="note-title">
<input id="title-field" type="text" placeholder="title your note">
</div>
<div id="note-body">
<textarea id="body-field"></textarea>
</div>
</notepad>
</main>
<footer>
<button id="btn-save">Save</button>
<button id="btn-delete">Delete / Clear </button>
</footer>
</body>
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js'></script>
<script type='text/javascript' src='app.js'></script>
</html>
I tried searching in the net for other notepads, but they aren't working on my blog, and here's the one that is finally working. I would really appreciate any kind of suggestions and assistance. T
If all you want to do is save to LocalStorage when save is clicked, then it would be as simple as saving the title and body variables to LocalStorage in the $('#btn-save').click() handler.
Assuming that (as #Nawed Khan guessed) you want to have the note saved without the user having to click save, then you'll want to make three changes:
In the main body of your $(document).ready() function, check for existing LocalStorage values, and if they exist, then set them on your $('#title-field') and $('#body-field') elements.
Add two new change handlers to your $('#title-field') and $('#body-field') elements. When these change handlers fire, get the title and body values from the elements and save them to LocalStorage.
In the $('#btn-save').click() and $('#btn-delete').click() handlers, reset the LocalStorage values of the active note.
You should find these links useful:
https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
https://api.jquery.com/change/
P.S. The information stored in LocalStorage can be lost if the user chooses to clear their browser data. If preservation of the data is vital, then implementing a solution using AJAX to connect to a database as #The Rahul Jha suggested would guarantee preservation of the data.
Yes , You can save the data in localStorage and fetch the data on page load. To set the localStorage item add below function in your script which is setting the item on keyup of textarea in localstorage.
$(document).on("keyup","#body-field",function(){
var text = $("#body-field").val();
localStorage.setItem("savedData", text);
});
Add below method to fetch the data from local storage
function loadDataFromLocalStorage(){
if (localStorage.getItem("savedData") !== null) {
$("#body-field").val(localStorage.getItem("savedData"))
}
}
And at last call the above method in $(document).ready() or page load to set the data back in text area after page load.
Put this inside the $(document).ready block:
$(“#title-field”).val(window.localStorage.getItem(“title”) || “”);
$(“#body-field”).val(window.localStorage.getItem(“body”) || “”);
$(“#title-field, #body-field”).change(function() {
var title = $(“#title-field”).val();
var body = $(“#body-field”).val();
window.localStorage.setItem(“title”, title);
window.localStorage.setItem(“body”, body)
})
The 2 first lines will load the text from the localStorage and sets the data on the corresponding inputs
The rest of the code is the part where the data is being saved to localStorage every time the value of #title-field OR #body-field changes.

localStorage does not save/show items

I do my ToDo list. (I learn vanilla JS). And I have some problem with saving some items to localStorage. When I use Google chrome(F12), I see undefiend. Maybe, I do not save correctly to localStorage. I tried to change var task to array, but it does not help. Pleas, show me my mistakes. I know, my code must be rewritten, it is my first code on JS. P.s. in console (in stackOverflow) I have that error
{
"message": "Uncaught SyntaxError: Unexpected identifier",
"filename": "https://stacksnippets.net/js",
"lineno": 348,
"colno": 6
}
but in my browser not.
var task = document.querySelector("ul");
var forTask;
function toLocal(){
forTask = task.innerHTML;
localStorage.setItem("forLocal",forTask);
}
function newElement(newChild) {
let btnDel= document.createElement("button");
btnDel.className = "fa fa-trash-o";
let myEd = document.getElementById("myEdit");
let spanClose1 = document.getElementsByClassName("close1")[0];
let spanRedact = document.getElementsByClassName("redact")[0];
let myDel = document.getElementById("myDelete");
let spanClose = document.getElementsByClassName("close")[0];
let spanYes = document.getElementsByClassName("yes")[0];
//create button
let divWithBut = document.createElement("div");
divWithBut.className = "forButt";
let btnRedact = document.createElement("button");
btnRedact.className = "fa fa-pencil";
//redact but
btnRedact.onclick = function(){
myEd.style.display = "block";
let editText = document.getElementById("editText");
let divWithText = divWithBut.parentElement.getElementsByClassName("todoPost")[0];
editText.value = divWithText.innerHTML;
editText.currentTarget;
spanRedact.onclick = function(){
divWithText.textContent = editText.value;
divWithText.className = "todoPost";
myEd.style.display = "none";
};
spanClose1.onclick = function() {
myEd.style.display = "none";
};
}
/*************************** */
/*done but*/
let doneBut = document.createElement("button");
doneBut.className = "fa fa-check-circle-o";
doneBut.onclick = function(){
let divWithText = divWithBut.parentElement.getElementsByClassName("todoPost")[0];
divWithText.classList.toggle("checked");
}
/******************* */
divWithBut.appendChild(btnRedact);
divWithBut.appendChild(doneBut);
divWithBut.appendChild(btnDel);
/******************/
//for index
let indexDiv = document.createElement("div");
indexDiv.className = "indexDiv";
let numbInd = 1;
indexDiv.innerHTML = numbInd;
/*********************************** */
//create arrow
let divWithArrow = document.createElement("div");
divWithArrow.className = "myArrow";
let arrowUP = document.createElement("i");
arrowUP.className = "fa fa-chevron-up";
let arrowDown = document.createElement("i");
arrowDown.className = "fa fa-chevron-down";
divWithArrow.appendChild(arrowUP);
divWithArrow.appendChild(arrowDown);
//for date
let date = new Date();
let curr_date = date.getDate();
let curr_month = date.getMonth()+1;
let curr_year = date.getFullYear();
let curr_hour = date.getHours();
let curr_minutes = date.getMinutes();
let d = (curr_date + "." + curr_month + "." + curr_year+"<br>"+curr_hour+":"+curr_minutes);
let divTime = document.createElement("div");
divTime.style.textAlign = "center";;
divTime.innerHTML = d;
//***************************/
let div1 = document.createElement("div");
div1.className = "timeComent";
let myli = document.createElement("li");
myli.className = "todoPost";
let addField = document.getElementById("addField").value;
task = document.createTextNode(addField);
myli.appendChild(task);
div1.appendChild(divTime);
div1.appendChild(indexDiv);
div1.appendChild(divWithArrow);
div1.appendChild(myli);
divWithBut.style.display = "flex";
div1.appendChild(divWithBut);
if (addField === '') {
alert("You must write something!");
} else {
document.getElementById("forToDo").appendChild(div1);
toLocal();
}
document.getElementById("addField").value = "";
//delete but
btnDel.onclick = function(){
myDel.style.display = "block";
spanClose.onclick = function() {
myDel.style.display = "none";
};
spanYes.onclick = function() {
myDel.style.display = "none";
div1.remove();
};
}
toLocal();
}
if(localStorage.getItem("forLocal")){
task.innerHTML = localStorage.getItem("forLocal");
}
*{
margin: 0;
padding: 0;
}
header{
width: 100%;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
overflow: auto;
}
.firstBar{
width: 100%;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
overflow: auto;
}
.indexDiv{
font-style: normal;
text-align: center;
color: #fff;
width: 15px;
height: 20px;
margin: 10px;
background-color: #888;
}
.fafaArrow{
font-size: 24px;
color: #000;
}
.timeComent{
margin-top: 15px;
margin-bottom: 15px;
display: flex;
justify-content:center;
align-items: center;
}
.numberpost{
padding: 5px;
color: rgb(255, 255, 255);
background: rgb(141, 112, 112);
}
.todoPost{
background-color: #eee;
width: 50%;
margin: 5px;
overflow: auto;
text-align: justify;
}
.shadow {
background: rgba(102, 102, 102, 0.5);
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
display: none;
}
.window {
width: 300px;
height: 50px;
text-align: center;
padding: 15px;
border: 3px solid #0000cc;
border-radius: 10px;
color: #0000cc;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
background: #fff;
}
.shadow:target {display: block;}
.redact {
display: inline-block;
border: 1px solid #0000cc;
color: #0000cc;
margin: 10px;
text-decoration: none;
background: #f2f2f2;
font-size: 14pt;
cursor:pointer;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
}
.redact:hover {
background-color: #68f462;
color: white;}
.close{
display: inline-block;
border: 1px solid #0000cc;
color: #0000cc;
margin: 10px;
text-decoration: none;
background: #f2f2f2;
font-size: 14pt;
cursor:pointer;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
}
.close:hover{
background-color: #f44336;
color: white;
}
/* Style the close button */
.close3 {
position: absolute;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
}
.yes {
display: inline-block;
border: 1px solid #0000cc;
color: #0000cc;
margin: 10px;
text-decoration: none;
background: #f2f2f2;
font-size: 14pt;
cursor:pointer;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
}
.yes:hover{
background-color: #68f462;
color: white;
}
.close1{
display: inline-block;
border: 1px solid #0000cc;
color: #0000cc;
margin: 10px;
text-decoration: none;
background: #f2f2f2;
font-size: 14pt;
cursor:pointer;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
}
.close1:hover{
background-color: #f44336;
color: white;
}
/* When clicked on, add a background color and strike out text */
div li.checked {
background: #888;
color: #fff;
text-decoration: line-through;
}
/* Add a "checked" mark when clicked on */
div li.checked::before {
content: '';
position: absolute;
border-color: #fff;
border-style: solid;
border-width: 0 2px 2px 0;
top: 10px;
left: 16px;
transform: rotate(45deg);
height: 15px;
width: 7px;
}
<!DOCTYPE html>
<html>
<head>
<title>TO DO List</title>
<link rel="stylesheet" type="text/css" href="styles/style.css" >
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body>
<header>
<input id="addField" type="text" size="70%" placeholder="Task" name="Task">
<button type="button" onclick="newElement()">Add</button>
</header>
<div>
<div class="firstBar">
<div class="fafaArrow">
<i class="fa fa-caret-up" ></i>
<i class="fa fa-caret-down"></i>
<input class="inptxt" type="text" size="50%" name="Task">
<i class="fa fa-filter"></i>
</div>
</div>
</div>
<ul id="forToDo" >
</ul>
<div id="myDelete" class="shadow">
<div class="window">Delete item?<br>
<span class="yes">Yes</span>
<span class="close">No</span>
</div>
</div>
<div id="myEdit" class="shadow">
<div class="window">
Edit text?<br>
<label>
<textarea id="editText"></textarea>
</label>
<span class="redact">Save</span>
<span class="close1">Cancel</span>
</div>
</div>
<script src="js/script2.js"></script>
</body>
</html>
When you add an element to the page, at a certain point you do this
task = document.createTextNode(addField);
Since task is a global variable (you declared it at the top), you're overshadowing it with the TextNode you're creating, so that when you then call toLocal and you do
forTask = task.innerHTML;
task has no innerHTML attribute, so it returns undefined.
Also, for some reason, you call toLocal again at the end of newElement. It's not the problem but it's something you may want to think about. I'm not sure it's what you want.
#TakayashiHarano gave a couple of hints to solve this, but I'm not sure what you want is just to have the latest element in the local storage. So I would re-write toLocal so that it takes a string (the text of the item) as input, writes it at the end of a JSON array (already populated with what was in the local storage previously), and puts the array back in local storage.
function toLocal(toAdd) {
let storage = localStorage.getItem('forLocal');
if (storage === null) {
storage = [];
} else {
storage = JSON.parse(storage);
}
storage.push(toAdd);
localStorage.setItem('forLocal', JSON.stringify(storage));
}
Then you should modify the part of the code that reads the local storage (the one at the end) to basically simulate adding a new item as you would do when creating a new task, but for each item in the parsed JSON coming from local storage.
To be fair, your code needs a good dose of rewriting to achieve this, so I'll just leave you with this as an exercise.
The following changes are needed.
1 - Set up two variables separably for the following task variable.
var task = document.querySelector("ul");
task = document.createTextNode(addField);
For example, "ulElement" for the first one, and "task" for the second one.
This is to prevent to override the previously defined value.
2 - Move the timing for obtaining the ul element and load localStorage.
function onReady() {
ulElement = document.querySelector("ul");
if(localStorage.getItem("forLocal")){
ulElement.innerHTML = localStorage.getItem("forLocal");
}
}
window.addEventListener('DOMContentLoaded', onReady, true);
To ensure the element existence, document.querySelector() should be called after the DOMContentLoaded event fired.
https://developer.mozilla.org/en-US/docs/Web/API/Window/DOMContentLoaded_event
3 - Delete toLocal(); in the end of the newElement() function.
As far as my testing code, there is no need this statement.

Categories