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

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";
}

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 retrieve data from local storage in javascript?

I'm making a hangman game and would like to store and retrieve the person's score and their username from the local storage and display it on the leader board div. How do I do this? I've seen most people use localStorage.get and localStorage.set but I'm not sure how to implement it here.
Thanks for the help.
This is my javascript code so far:
function storeUserDetails() {
var userObject = {};
userObject.name = document.getElementById("nameinput").value;
userObject.username = document.getElementById("usernameinput").value;
userObject.password = document.getElementById("passinput").value;
userObject.repeatpassword = document.getElementById("repeatpassinput").value;
userObject.topscore = 0;
localStorage[userObject.username] = JSON.stringify(userObject);
document.getElementById("result").innerHTML = "<b>Registration
Successful<br> Please <a href = '../PHP/login.php'><font color =
'orangered'>login</font></a></b>";
}
function checkLogin() {
if (localStorage.loggedInUsername !== undefined) {
var userObj = JSON.parse(localStorage[localStorage.loggedInUsername]);
}
}
function login() {
var username = document.getElementById("usernameinput").value;
if (localStorage[username] === undefined) {
document.getElementById("result").innerHTML = "<b>Username not found. Please sign up.</b>";
return;
} else {
var userObj = JSON.parse(localStorage[username]); //Convert to object
var password = document.getElementById("passinput").value;
if (password === userObj.password) {
localStorage.loggedInUsername = userObj.username;
document.getElementById("result").innerHTML = "";
window.location = "loggedin.php";
/*sessionStorage.setItem('status', 'logged in');*/
} else {
document.getElementById("result").innerHTML = "<b>Password incorrect. Please try again.</b>"
}
}
}
function updateScore() {
rankingTable = document.getElementById("leaderboardcontainer");
tableData = document.getElementById("content");
//Username and score to be displayed here.
}
You should use getItem, setItem and removeItem methods as shown in the documentation.
https://developer.mozilla.org/it/docs/Web/API/Window/localStorage

Why searchbox become lagging when typing word to search data in CSV?

I developed the store locator using open street map and leaflet. The problem is when I want to type in searchbox it will become lagging to finish the word. That store locator read from the CSV file that has 300++ data. Below is the code for the searchbox:
var locationLat = [];
var locationLng = [];
var locMarker;
var infoDiv = document.getElementById('storeinfo');
var infoDivInner = document.getElementById('infoDivInner');
var toggleSearch = document.getElementById('searchIcon');
var hasCircle = 0;
var circle = [];
//close store infor when x is clicked
var userLocation;
$("#infoClose").click(function() {
$("#storeinfo").hide();
if (map.hasLayer(circle)) {
map.removeLayer(circle);
}
});
var listings = document.getElementById('listingDiv');
var stores = L.geoJson().addTo(map);
var storesData = omnivore.csv('assets/data/table_1.csv');
function setActive(el) {
var siblings = listings.getElementsByTagName('div');
for (var i = 0; i < siblings.length; i++) {
siblings[i].className = siblings[i].className
.replace(/active/, '').replace(/\s\s*$/, '');
}
el.className += ' active';
}
function sortGeojson(a,b,prop) {
return (a.properties.name.toUpperCase() < b.properties.name.toUpperCase()) ? -1 : ((a.properties.name.toUpperCase() > b.properties.name.toUpperCase()) ? 1 : 0);
}
storesData.on('ready', function() {
var storesSorted = storesData.toGeoJSON();
//console.log(storesSorted);
var sorted = (storesSorted.features).sort(sortGeojson)
//console.log(sorted);
storesSorted.features = sorted;
//console.log(storesSorted)
stores.addData(storesSorted);
map.fitBounds(stores.getBounds());
toggleSearch.onclick = function() {
//var s = document.getElementById('searchbox');
//if (s.style.display != 'none') {
//s.style.display = 'yes';
//toggleSearch.innerHTML = '<i class="fa fa-search"></i>';
//$("#search-input").val("");
//search.collapse();
//document.getElementById('storeinfo').style.display = 'none';
//$('.item').show();
//} else {
//toggleSearch.innerHTML = '<i class="fa fa-times"></i>';
//s.style.display = 'block';
//attempt to autofocus search input field when opened
//$('#search-input').focus();
//}
};
stores.eachLayer(function(layer) {
//New jquery search
$('#searchbox').on('change paste keyup', function() {
var txt = $('#search-input').val();
$('.item').each(function() {
if ($(this).text().toUpperCase().indexOf(txt.toUpperCase()) != -1) {
$(this).show();
} else {
$(this).hide();
}
});
});
I dont know what is the cause of the lag in the search box. It is something wrong in code or the csv file? Thank you
Every iteration of $('.item').each is causing a layout change because $(this).hide() or $(this).show() causes the item to removed/added to the DOM as the style is set to display:none back and forth. DOM manipulations and the corresponding layout changes are expensive.
You can consider accumulating the changes and doing one batch update to the DOM using a function like appendChild

removeChild is not a function

window.onload = initPage;
var firstname = false;
var lastname = false;
function initPage() {
addEventHandler(document.getElementById("firstname"), "blur", verifyFirst);
addEventHandler(document.getElementById("lastname"), "blur", verifyLast);
addEventHandler(document.getElementById("submit"), "click", showName);
}
function verifyFirst(e) {
var me = getActivatedObject(e);
if (me.value === "") {
me.className = "error";
me.focus();
me.select();
return;
}
else {
me.className = "";
firstname = true;
enabledButton();
}
}
function verifyLast(e) {
var me = getActivatedObject(e);
if (me.value === "") {
me.className = "error";
me.focus();
me.select();
return;
}
else {
me.className = "";
lastname = true;
enabledButton();
}
}
function enabledButton() {
if (firstname && lastname) {
document.getElementById("submit").disabled = false;
}
else {
document.getElementById("submit").disabled = true;
}
}
function showName() {
var first = document.getElementById("firstname").value;
var last = document.getElementById("lastname").value;
var word = first.toLowerCase() + last.toLowerCase();
for (var i = 0; i < word.length; i++) {
var letter = word.charAt(i);
var img = document.createElement("img");
img.setAttribute("src", "images/" + letter + ".png");
img.setAttribute("style", "left:" + 50 * i);
document.getElementById("displayname").appendChild(img);
}
var t = setInterval(removeName, 2000);
}
function removeName() {
var display = document.getElementById("displayname").getElementsByTagName("img");
var lengthOfDisplay = display.length;
for (var i = 0; i < lengthOfDisplay; i++) {
document.getElementById("displayname").removeChild(display[i]);
}
var t = setInterval(showName, 2000);
}
This is my current code that I am working on. I am creating a website with two input fields for first name and last name. On blur of each field after they are verified they will enabled the submit button. When the submit button is clicked, it will combine the first and last name and then separate each letter and call an image that will relate to each letter entered and display it on the displayname div.
Here is where I get the problem:
What I want is to display the image then remove the images and display it again continuously using setInterval. (i.e. the name spelled with the images will be flashing). unfortunately with my code when I try to remove the images using the removeChild function, I get an error of:
UPDATE
Uncaught TypeError: Failed to execute 'removeChild' on 'Node': parameter 1 is not of type 'Node'.
Below is an image of the of the inspection tool with the error and line that is getting the error.
Why am I getting this error when I am asking it to remove the images with removeChild(display[i])?
Replace line 68 with
document.getElementById("displayname").innerHTML = '';
Change the code on the line 68 from this
document.getElementById("displayname".removeChild(display[i]));
to this
document.getElementById("displayname").removeChild(display[i]);
removeChild() is a method applicable to a Node (and not a string or a selector as you have used in your code).
document.getElementById("displayname").removeChild(display[i])); should be the appropriate syntax.

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