How to use localStorage to cache button result? - javascript

I have a button that I am making completely out of JS.
I want to save whether it was in a true or false state so that if a user leaves the page the button will be in the same state when they return. I'd like to use localStorage but I'm relatively new to JS so they may be a better solution.
Current Code:
var btn;
var btn = document.createElement("BUTTON");
btn.onclick = function() {myFunction()};
btn.style.height = "100%";
btn.style.width = "98%";
btn.style.border = "0px";
btn.innerHTML = "CLICK ME";
btn.id = "toggle";
document.getElementById("button").appendChild(btn);
function myFunction() {
document.getElementById('notepad').classList.toggle('hide'); return false
}
Edit Code:
window.onload = function initBt(){
var buttonState = localStorage.getItem('mybutton');
if ( null !== buttonState )
{
buttonState && document.getElementById('notepad').classList.add('hide');
}
}
var btn;
var btn = document.createElement("BUTTON");
btn.onclick = function() {myFunction()};
btn.style.height = "100%";
btn.style.width = "98%";
btn.style.border = "0px";
btn.innerHTML = "CLICK ME";
btn.id = "toggle";
document.getElementById("button").appendChild(btn);
function myFunction() {
var bt = document.getElementById('notepad');
bt.classList.toggle('hide');
localStorage.setItem('mybutton', bt.classList.contains('hide'))
return false;
}

you can use following functions in youir code to store and retrieve the button state:
localStorage documentation
function store(key, data)
{
localStorage.setItem(key, JSON.stringify(data));
}
function retrieve(key)
{
var data = localStorage.getItem(key);
return data ? JSON.parse(data) : null;
}
function remove(key)
{
localStorage.removeItem(key);
}
usage examples:
store('mybutton', buttonState);
var buttonState = retrieve('mybutton');
if ( buttonState !== null )
{
/* set button State*/
}
else
{
/* state has not been saved before, initialise */
}
NOTE since localStorage can handle ONLY string values, we use JSON.stringify when saving to make a string out of data and JSON.parse when retrieving in order to store and retrieve arbitrary data (that are of course JSON valid structures)
For your updated question try the following (it would be more helpfull if the whole html structure was added since some elements are missing, but anyway):
// include the needed localStorage manipulation methods
function store(key, data)
{
localStorage.setItem(key, JSON.stringify(data));
}
function retrieve(key)
{
var data = localStorage.getItem(key);
return data ? JSON.parse(data) : null;
}
function remove(key)
{
localStorage.removeItem(key);
}
// create and initialise the button
var btn = document.createElement("BUTTON");
btn.onclick = function() {myFunction()};
btn.style.height = "100%";
btn.style.width = "98%";
btn.style.border = "0px";
btn.innerHTML = "CLICK ME";
btn.id = "toggle";
document.getElementById("button").appendChild(btn);
var buttonState = retrieve('mybutton');
// make sure at this point element with id="notepad" exists on page
if ( null !== buttonState )
{
buttonState && document.getElementById('notepad').classList.add('hide');
}
function myFunction() {
var bt = document.getElementById('notepad');
bt.classList.toggle('hide');
store('mybutton', bt.classList.contains('hide'));
return false;
}
For a flexible caching library for web/browser that can support a variety of storage mechanisms (and also support for server-side php and node.js) check Unicache (ps. I am the author)
There are of course other libraries as well (eg localForage)

Related

Two different js under two button on one page

On my page I have two buttons, button 1 and button 2. Under those buttons I want to get the value of a javascript per button, so that I can switch the javascript per button. I am a beginner and I can really use some help for this :) I have tried everything that is possible at my knowledge level. I searched on Stack but didn't find anything close to what I needed. Hopefully you can help me.
EDIT: Ive updated my snippet. Now one button is working en de graph is coming. When i push the second button nothing happens.
function myFunction1() {
var x = document.getElementById('3d-graph');
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
function myFunction2() {
var x = document.getElementById('graph');
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
var elem = document.getElementById("graph");
var drivertwo = neo4j.v1.driver("bolt+routing://90bfd895.databases.neo4j.io", neo4j.v1.auth.basic("got", "got"),{encrypted: true});
var sessiontwo = drivertwo.session();
var starttwo = new Date()
sessiontwo
.run('MATCH (n)-[r]->(m) RETURN { id: id(n), label:head(labels(n)), community:n.title, caption:n.title, size:n.title } as source, { id: id(m), label:head(labels(m)), community:n.title, caption:m.title, size:m.title } as target, { weight:r.title, type:type(r), community:case when n.title < m.title then n.title else m.title end} as rel LIMIT $limit', {limit: 1000})
.then(function (result) {
var nodes = {}
var links = result.records.map(r => {
var source = r.get('source');source.id = source.id.toNumber();
nodes[source.id] = source;
var target = r.get('target');target.id = target.id.toNumber();
nodes[target.id] = target;
var rel = r.get('rel'); if (rel.weight) { rel.weight = rel.weight.toNumber(); }
return Object.assign({source:source.id,target:target.id}, rel);
});
sessiontwo.close();
console.log(links.length+" links loaded in "+(new Date()-starttwo)+" ms.")
var gData = { nodes: Object.values(nodes), links: links}
var Graph = ForceGraph()(elem)
.graphData(gData)
.nodeAutoColorBy('label')
.linkDirectionalParticles('weight')
.linkDirectionalParticleSpeed(0.001)
.nodeLabel(node => `${node.label}: ${node.caption}`)
.onNodeHover(node => elem.style.cursor = node ? 'pointer' : null);
});
var elem = document.getElementById('3d-graph');
var driver = neo4j.v1.driver("bolt+routing://90bfd895.databases.neo4j.io", neo4j.v1.auth.basic("got", "got"),{encrypted: true});
var session = driver.session();
var start = new Date()
session
.run('MATCH (n)-[r]->(m) RETURN { id: id(n), label:head(labels(n)), community:n.title, caption:n.title, size:n.title } as source, { id: id(m), label:head(labels(m)), community:n.title, caption:m.title, size:m.title } as target, { weight:r.title, type:type(r), community:case when n.title < m.title then n.title else m.title end} as rel LIMIT $limit', {limit: 1000})
.then(function (result) {
var nodes = {}
var links = result.records.map(r => {
var source = r.get('source');source.id = source.id.toNumber();
nodes[source.id] = source;
var target = r.get('target');target.id = target.id.toNumber();
nodes[target.id] = target;
var rel = r.get('rel'); if (rel.weight) { rel.weight = rel.weight.toNumber(); }
return Object.assign({source:source.id,target:target.id}, rel);
});
session.close();
console.log(links.length+" links loaded in "+(new Date()-start)+" ms.")
var gData = { nodes: Object.values(nodes), links: links}
var Graph = ForceGraph3D()(elem)
.graphData(gData)
.nodeAutoColorBy('label')
.linkDirectionalParticles('weight')
.linkDirectionalParticleSpeed(0.001)
.nodeLabel(node => `${node.label}: ${node.caption}`)
.onNodeHover(node => elem.style.cursor = node ? 'pointer' : null);
});
<script src="https://unpkg.com/force-graph"></script>
<script src="https://unpkg.com/3d-force-graph"></script>
<script src="https://cdn.rawgit.com/neo4j/neo4j-javascript-driver/1.2/lib/browser/neo4j-web.min.js"></script>
<button onclick="myFunction1()">Try it</button>
<button onclick="myFunction2()">Try it</button>
<p id="graph"></p>
<p id="3d-graph"></p>
The buttons work correctly. The reason you don't see one of the images is that you declared var elem twice.
If you replace elem by elem2 in var elem = document.getElementById('3d-graph'); and in the code below that, then it will be fixed.
But it would be better to wrap the image loading in a separate function, like this:
function loadImage(elementId) {
var elem = document.getElementById(elementId);
...
...
}
and then call this function twice:
loadImage('graph');
loadImage('3d-graph');
try this and let me know if there are other problems:
<button id='1' onclick="myFunction(this)">button 1</button>
<button id='2' onclick="myFunction(this)">button 2</button>
<p id="graph"></p>
<p id="3d-graph"></p>
Passing "this" to myFunction, the "elem", will be the button you click.
Remember that is better to use .addEventListener('click', function(ev){}) instead "onclick=function()"
function myFunction(elem) {
document.getElementById("graph").innerHTML = "ID:" + elem.id;
document.getElementById("3d-graph").innerHTML = "ID:" + elem.id;
}
I don't know what the code below what the rest of the code will do, and if it works, but i see a lot of duplications. If you can, try to put all the neo4j call inside a function, so that you can use this every time you need it.

How to remove last <li> child together with it's local storage?

I'm doing a to do list and I want to add, remove and clear tasks together with their local storage. Add and clear work but I failed to make remove work.
I tried using element.lastChild but removing it didn't work.
var last = document.getElementById("list").lastChild.innerHTML;
Here is my code
var remove = function(){
var listItems = document.getElementById("list").getElementsByTagName("li");
var last = listItems[listItems.length - 1];
last.parentNode.removeChild(last);
removeStore(last);
}
// localStorage
function store() {
window.localStorage.myToDoList = list.innerHTML;
}
function clearStore() {
localStorage.clear();
}
function removeStore(item) {
localStorage.removeItem(item);
}
Remove works only for removing tasks but I'm getting an error after the first clicking on remove button
"TypeError: last.parentNode is null"
and after the last one:
TypeError: document.getElementById(...).lastChild is null
https://codepen.io/aggat/pen/PrQRYj
You can replace your javascript part of the code with my part. The changed part is commented in capitals and explained with the purpose of change.
var add = function(){
var listItems = document.getElementById("list").getElementsByTagName("li");
var what = document.getElementById('what').value;
var li = document.createElement('li');
if (what.length > 0) {
li.appendChild(document.createTextNode(what));
list.appendChild(li);
store()
//document.getElementById('what').placeholder = "What do I have to do?";
} else {
li.appendChild(document.createTextNode("Task number " + (listItems.length + 1)));
list.appendChild(li);
store();
}
}
// I HAVE TO CHANGE THE LOGIC OF THIS FUNCTION COMPLETELY
// THIS FUNCTION TAKES VALUE FROM LOCAL STORAGE, CHECKS FOR EXISISTENCE OF
// LAST li ELEMENT HTML AND IF FIND IT, THEN REMOVE IT FROM LOCAL STORAGE VALUE
// AND SET NEW VALUE BACK IN LOCAL STORAGE
function rem() {
//var a = document.getElementById("list").lastChild.innerHTML;
//localStorage.last = a;
var aValue = localStorage.getItem("myToDoList");
console.log(aValue);
var listItems = document.getElementById("list").getElementsByTagName("li");
console.log(listItems);
if (listItems.length > 0) {
var last = listItems[listItems.length - 1];
if (last) {
var lastHtml = last.outerHTML;
console.log(lastHtml);
var indexAtWhichLastElementPresent = aValue.indexOf(lastHtml);
if (indexAtWhichLastElementPresent > -1) {
// Removes the lastElementHtml part from local storage value
aValue = aValue.substring(0, indexAtWhichLastElementPresent) + aValue.substring(indexAtWhichLastElementPresent + lastHtml.length);
}
}
}
localStorage.setItem("myToDoList", aValue);
}
var remove = function(){
var listItems = document.getElementById("list").getElementsByTagName("li");
console.log(listItems);
var last = listItems[listItems.length - 1];
rem(); // CHANGED THE CALLING ORDER. FIRST REMOVE DATA FROM LOCAL STORAGE AND THEN ELEMENT WILL BE REMOVED
last.parentNode.removeChild(last);
// TAKE OUT THE REMOVE FUNCTION FROM INSIDE OF THIS FUNCTION SO THAT IT CAN
// BE USED BY SOME OTHER FUNCTION IN FUTURE
if (listItems.length === 0){
alert();
}
}
var clearAll = function(){
var myNode = document.getElementById("list");
while (myNode.firstChild) {
myNode.removeChild(myNode.firstChild);
clearStore();
}
alert();
}
// localStorage
function store() {
window.localStorage.myToDoList = list.innerHTML;
}
function clearStore() {
localStorage.clear();
}
/*function removeStore(item) {
localStorage.removeItem(item);
}*/
function getValues() {
var storedValues = window.localStorage.myToDoList;
if(!storedValues) {
list.innerHTML = '';
}
else {
list.innerHTML = storedValues;
}
}
getValues();
//modal box
var modal = document.getElementById("myModal");
//button that opens the modal
var btn = document.getElementById("myBtn");
//<span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
//open the modal
function alert() {
modal.style.display = "block";
}
//clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
//clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
Please comment if in case you face any problem in implementing this solution.
Your last is available only if you have entries in your todo list. Initially, and after clearing all items from your todo list, last in your remove() function will be undefined as your list is empty.
To avoid this error, conditionally check for the presence of entries in your todo list.
var remove = function(){
var listItems = document.getElementById("list").getElementsByTagName("li");
var last = listItems[listItems.length - 1];
if (last) {
last.parentNode.removeChild(last);
}
... rest of your code
}
And after removing item from your list, set your localstorage with current elements of your list. This will update your localstorage with currrent items in the list.
if (last) {
last.parentNode.removeChild(last);
window.localStorage.myToDoList = document.getElementById("list").innerHTML; // or call your store(); function
}
Hope this is helpful :)

Firebase: Using callback function to decide whether data is in the database

I am creating search bar, which shows results from database dynamically on keypress, when they match the string that is in the search bar. Also when the string doesn't match anything in my database, I want to show message to user, that nothing matches his input. Problem is that I don't know how to do this in javaScript. I tried using callback function, but my implementation doesn't work. It is my first time using callback function, so I guess something is not right. Can anybody help me?
Here is simplified code:
var bars = firebase.database().ref("bars").orderByChild("rating");
var types = firebase.database().ref("types");
var searcher = document.getElementById("searcher");
var results = document.getElementById("searchResults");
function search(){
var value = searcher.value.toUpperCase();
clearTimeout(timeout);
timeout = setTimeout(function () {
if(value == null || value == ""){
results.style.display = "none";
} else{
results.innerHTML = "";
//callback function here
function findResults(callback) {
types.once("value").then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var type = childSnapshot.key;
if(type.toUpperCase().startsWith(value)){
results.style.display = "block";
var typeItem = createDiv("result-item");
typeItem.innerHTML = type;
results.append(typeItem);
}
callback(true);
});
});
bars.once("value").then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var bar = childSnapshot.key;
if(bar.toUpperCase().startsWith(value)){
results.style.display = "block";
var barItem = createDiv("result-item");
barItem.innerHTML = type;
results.append(barItem);
}
callback(true);
});
});
}
//This needs to work, when callback didn't return true
findResults(function(callback){
if(!callback){
var empty = createDiv("emptyResult");
empty.innerHTML = "No matching results";
results.appendChild(empty);
results.style.display = "block";
}
});
}
}, 400);
}
function createDiv(name){
var div = document.createElement("div");
div.className = name;
return div;
1.Let me start by pointing out that querying the Firebase Database on Keypress can be very expensive, since you'll be downloading data more frequently and Firebase has a price on data downloaded. I recommend querying the database when the user presses Enter or a Search Button.
2.I don't see why you need a callback function for this. You can use plain functions to achieve that. Like this:
function search(){
var value = searcher.value.toUpperCase();
clearTimeout(timeout);
timeout = setTimeout(function () {
if(value == null || value == ""){
results.style.display = "none";
} else{
results.innerHTML = "";
types.once("value").then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var type = childSnapshot.key;
var foundUnderTypes = false;
if(type.toUpperCase().startsWith(value)){
results.style.display = "block";
var typeItem = createDiv("result-item");
typeItem.innerHTML = type;
results.append(typeItem);
foundUnderTypes = true;
}
bars.once("value").then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var bar = childSnapshot.key;
if(bar.toUpperCase().startsWith(value)){
results.style.display = "block";
var barItem = createDiv("result-item");
barItem.innerHTML = type;
results.append(barItem);
}
else{
if(!foundUnderTypes)
emptyResult();
}
});
});
});
});
}
}, 400);
}
function emptyResult(){
var empty = createDiv("emptyResult");
empty.innerHTML = "No matching results";
results.appendChild(empty);
results.style.display = "block";
}

Javascript Object passing itself in as a parameter

I have an object with some information. On the other hand I have a store, holding many objects of this object type.
The single object should be able to delete itself from this store.
My store knows a function "DeleteObjectFromStore" with a parameter of this object.
Now I want to pass in the object itself but I don't know which syntax to use.
The store:
class NoteStore {
constructor() {
this.notes = []; // Collection of all notes
}
DeleteNote(note) { // Delete this object from the store
var index = this.notes.indexOf(note);
if (index > -1)
array.splice(index, 1);
}
}
And my object
class Note {
constructor(noteTitle, noteText, noteStore) {
this.title = noteTitle; // name
this.text = noteText; // content
this.store = noteStore; // dataStore
}
CreateDeleteButton(parentDiv) { // Create a button for deleting itself
var data = this.store;
var deleteBtn = document.createElement("input");
deleteBtn.type = "button";
deleteBtn.value = "Delete";
deleteBtn.onclick = function() {
data.DeleteNote(); // <= missing parameter!
}
parentDiv.appendChild(deleteBtn);
}
}
So using the keyword this is not correct. Then I would pass in the button.
Could someone help me out?
Try using a name for this outside the function:
CreateDeleteButton(parentDiv) { // Create a button for deleting itself
var data = this.store;
var noteObj = this;
var deleteBtn = document.createElement("input");
deleteBtn.type = "button";
deleteBtn.value = "Delete";
deleteBtn.onclick = function() {
data.DeleteNote( noteObj );
}
parentDiv.appendChild(deleteBtn);
}

localStorage clearing when I use split()

I want to create an array of names based on localStorage variable called "names". I use the String.split() to detect a new line which seems to work well, but not if I refresh the page more than once.
var names = localStorage.names;
if (!names) {
textArea.style.display = "block";
mybutton.style.display = "block";
} else {
textSplit = localStorage.names.split(/\n/);
copyInput1.innerHTML = textSplit[0];
copyInput2.innerHTML = textSplit[1];
copyInput3.innerHTML = textSplit[2];
}
document.getElementById("textArea").focus();
var showText = function() {
var text = textArea.value;
localStorage.names = text;
textSplit = localStorage.names.split(/\n/);
copyInput1.innerHTML = textSplit[0];
copyInput2.innerHTML = textSplit[1];
copyInput3.innerHTML = textSplit[2];
}
mybutton.onclick = showText;
clearbutton.onclick = localStorage.clear();
Any help appreciated.
You are executing clear() on localStorage which explains why it clears:
clearbutton.onclick = localStorage.clear();
Change this to:
clearbutton.onclick = localStorage.clear;
This way you're referencing the function instead.

Categories