I'm making a food sharing site using firebase I'm trying to add a delete post option so when a food item is taken the user can delete the post so they aren't contacted about something they've already given away. I have managed to get the firebase remove function working but it just deletes all posts not just one. I'm using the push option when sending the data to my database as I need users to be able to make multiple posts but I don't know what the name of the post ids are to select them.
This is the code that sends the donations to the database
function submitDonation() {
var user = firebase.auth().currentUser;
if(user) {
var userid = user.uid;
var email = user.email;
var firebaseRef = firebase.database().ref();
firebaseRef.child("Donations").push({
user: userid,
email: email,
food: document.getElementById("foodType").value,
animal: document.getElementById("animalType").value,
expire: document.getElementById("expirationDate").value,
travel: document.getElementById("travelDistance").value,
location: document.getElementById("what3wordsLocation").value,
contact: document.getElementById("contactPreference").value,
time: document.getElementById("timePreference").value
});
}
}
and this is the code retrieving and drawing the data on the page. I'm using jquery to display my posts so sorry it looks a bit messy but I've basically got a button that calls a function and I need the button's id to match the id of the post but I don't know how to call that. Any help would be much appreciated. I'm still relatively new to firebase so still working on the basics aha.
var rootRef = firebase.database().ref().child("Donations");
rootRef.on("child_added", snap => {
var food = snap.child("food").val();
var animal = snap.child("animal").val();
var expire = snap.child("expire").val();
var travel = snap.child("travel").val();
var location = snap.child("location").val();
var contact = snap.child("contact").val();
var time = snap.child("time").val();
$("#listingDonations").append(
"<div id='donationBox' class='three columns'><div id='donationItem'><button onclick='deletePost()'>Delete</button><p><b>Type of Food:</b> " + food + "</p><p><b>Type of Animal:</b> " + animal + "</p><p><b>Expiration Date:</b> " + expire + "</p><p><b>Travel Distance:</b> " + travel + "</p><p><b>Contact Details:</b> " + contact + "</p><p><b>Preferred Contact Time:</b> " + time + "</p><a href='https://www.what3words.com/"+ location +"'>Location</a></div></div>"
);
})
function deletePost() {
}
Ive deleted the code I'd written in the deletePost function as it didn't work and is probably wrong anyway.
Related
I am trying to build a GSM Gmail addon that will open a card in the compose window and have several fields and then will generate a template and add it to the email. I have several variables containing HTML content and several containing fields from the card. I have almost gotten that done. The last thing that I need to do is to specify a subject, that will be the same every time, and specify recipients that will be based on a text field in the card.
Here is my code. I have 2 files, one gs code file, and one json manifest file.
Manifest.json:
{
"timeZone": "America/Chicago",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER",
"oauthScopes": ["https://www.googleapis.com/auth/gmail.addons.current.action.compose", "https://www.googleapis.com/auth/gmail.addons.current.message.readonly", "https://www.googleapis.com/auth/gmail.addons.execute", "https://www.googleapis.com/auth/script.locale"],
"runtimeVersion": "V8",
"addOns": {
"common": {
"name": "Review Published Email Template",
"logoUrl": "https://goodbookreviews.page/Logo.png",
"useLocaleFromApp": true,
"universalActions": [{
"label": "Book Review ",
"openLink": "https://www.goodbookreviews.page"
}]
},
"gmail": {
"contextualTriggers": [{
"unconditional": {
},
"onTriggerFunction": "onGmailMessage"
}],
"composeTrigger": {
"selectActions": [{
"text": "Use Template",
"runFunction": "onGmailCompose"
}],
"draftAccess": "NONE"
}
}
}
}
code.js:
function onGmailCompose(e) {
console.log(e);
var header = CardService.newCardHeader()
.setTitle('Use Template')
.setSubtitle('Use the template for sending an email after a review has been published.');
// Create text input for entering the cat's message.
var input = CardService.newTextInput()
.setFieldName('email')
.setTitle('Email')
.setHint('What is the readers email address?');
var input2 = CardService.newTextInput()
.setFieldName('FName')
.setTitle('First Name')
.setHint('What is the readers first name?');
var input3 = CardService.newTextInput()
.setFieldName('BookTitle')
.setTitle('Reviewed Book Title')
.setHint('What is the title of the book reviewed?');
var input4 = CardService.newTextInput()
.setFieldName('BookAuthor')
.setTitle('Reviewed Book Author')
.setHint('Who is the author of the book reviewed?');
// Create a button that inserts the cat image when pressed.
var action = CardService.newAction()
.setFunctionName('useTemplate');
var button = CardService.newTextButton()
.setText('Use Template')
.setOnClickAction(action)
.setTextButtonStyle(CardService.TextButtonStyle.FILLED);
var buttonSet = CardService.newButtonSet()
.addButton(button);
// Assemble the widgets and return the card.
var section = CardService.newCardSection()
.addWidget(input)
.addWidget(input2)
.addWidget(input3)
.addWidget(input4)
.addWidget(buttonSet);
var card = CardService.newCardBuilder()
.setHeader(header)
.addSection(section);
return card.build();
}
function useTemplate(e) {
console.log(e);
var email = e.formInput.email;
var FName = e.formInput.FName;
var Title = e.formInput.BookTitle;
var Author = e.formInput.BookAuthor;
var now = new Date();
var htmlIntro = '<p>Hello, </p>';
var html2 = '<p> Thank you for writing a book review at Good Book Reviews on</p>';
var html3 = '<p>by</p>';
var html4 = '<p>. You Review has been published to our site. Any personal information you included was NOT published, including first name, last name, age, and email address. Only info you wrote about the book was published. You can see it right here! If you need anything else, feel free to contact us at support#goodbookreviews.page or reply to this email to contact us. <br> Happy Reading,<br> The Book Review Team</p>';
var message = htmlIntro + FName + html2 + Title + html3 + Author + html4;
var response = CardService.newUpdateDraftActionResponseBuilder()
.setUpdateDraftBodyAction(CardService.newUpdateDraftBodyAction()
.addUpdateContent(message, CardService.ContentType.MUTABLE_HTML)
.setUpdateType(CardService.UpdateDraftBodyType.IN_PLACE_INSERT))
.build();
return response;
}
function onGmailMessage(e) {
console.log(e);
var header = CardService.newCardHeader()
.setTitle('Unavailable')
.setSubtitle('Open the compose window to use template');
var card = CardService.newCardBuilder()
.setHeader(header);
return card.build();
}
Can someone please tell me how to do this? Thanks!
Your "p" tags create extra newlines. Try something like
var htmlIntro = '<p>Hello, ';
var html2 = 'Thank you for writing a book review at Good Book Reviews on ';
var html3 = ' by ';
var html4 = '. You Review has been published to our site. Any personal information you included was NOT published, including first name, last name, age, and email address. Only info you wrote about the book was published. You can see it right here! If you need anything else, feel free to contact us at support#goodbookreviews.page or reply to this email to contact us. <br> Happy Reading,<br> The Book Review Team</p>';
var message = htmlIntro + FName + html2 + Title + html3 + Author + html4;
Or, if you use V8 engine, even simpler
var message = `<p>Hello, ${FName} Thank you for writing a book review at Good Book Reviews on ${Title} by ${Author}. Your Review has been published to our site. Any personal information you included was NOT published, including first name, last name, age, and email address. Only info you wrote about the book was published. You can see it right here! If you need anything else, feel free to contact us at support#goodbookreviews.page or reply to this email to contact us.</p>
<br>
<p>Happy Reading,</p>
<br>
<p>The Book Review Team</p>
`
I am creating admin panel in website and I am using firebase as a database in backend.I am able to display listing where onclick of accept status of listing get changed to 'accepted' but the thing is when status get change to accepted then listing in display should get filter and display only pending listing
pl.js
var firebaseheadingRef = firebase.database().ref().child("user");
function accept(userId) {
var nodeRef = firebase.database().ref("/user/" + userId + "/listing/status");
return nodeRef.set('accept');
}
function reject(userId) {
var nodeRef = firebase.database().ref("/user/" + userId + "/listing/status");
return nodeRef.set('reject');
}
firebaseheadingRef.on('child_added',datasnapshot=>{
var title= datasnapshot.child("listing").child("title").val();
var userid= datasnapshot.child("username").val();
var type= datasnapshot.child("listing").child("title").val();
var publisheddate= datasnapshot.child("listing").child("publish").val();
var expirydate= datasnapshot.child("listing").child("expire").val();
$("#tablebody").append("<tr><td>"+title+"</td><td>"+userid+"</td><td>"+type+"</td><td>"+publisheddate+"</td><td><button type=button id=accept onclick=accept('" + datasnapshot.key + "')>Accept</button><button type=button onclick=reject('" + datasnapshot.key + "')>Reject</button></td></tr>");
});
should display filter listing where status = pending
Database
You can use the orderByChild method along with the equalTo method to sort the children by status property
firebaseheadingRef.orderByChild("/listing/status").equalTo("pending")
.on('child_added',datasnapshot=>
{
//Enter your code here
});
Try changing the line
var firebaseheadingRef = firebase.database().ref().child("user");
to
var firebaseheadingRef = firebase.database().ref('/user');
I am having issues trying to figure this out. I come from a SQL background and am new to Firebase database. I am building a website that sells individual videos online. What I am trying to do seems simple but I can't for the life of me get it to work.
I want to show a page listing only the videos a user has purchased and not the entire list of videos available. Obviously, because I only want the user to access what they have purchased. Currently, I can display the list of all videos and category heading for each category. I can't figure out how to restrict this list to display only the videos the user has purchased.
Here is my Database Structure
.
As you can see I have videos and their info in a "videos" collection and users in a "users" collection. Under each user is a "pvideos" collection that shows the id of each video the user has purchased.
Any ideas on how I might write this to restrict the list to match only the videos the user has purchased?
Included is the code that displays the category heading and videos (currently) for all available videos regardless of purchase status.
var series = db.child('videos').orderByKey();
series.once('value')
.then(function (snapshot) {
snapshot.forEach(function (childSnapshot) {
var videoseries = childSnapshot.key;
console.log(videoseries);
var seriesheading = document.createElement('h3');
seriesheading.textContent = videoseries;
seriesheading.setAttribute('class', 'bg-color-2');
document.getElementById("container").appendChild(seriesheading);
var videodata = db.child('videos/' + videoseries).orderByKey();
videodata.once('value')
.then(function (snapshot) {
snapshot.forEach(function (childSnapshot) {
var videoid = childSnapshot.key;
var vimeo = childSnapshot.child('vimeo').val();
var videoname = childSnapshot.child('name').val();
var videolength = childSnapshot.child('length').val();
var videodesc = childSnapshot.child('desc').val();
console.log(videoid);
console.log(vimeo);
console.log(videoname);
console.log(videolength);
console.log(videodesc);
var videolisting = document.createElement('div');
videolisting.setAttribute('class', 'row');
videolisting.innerHTML = "<div class='col-md-6'><div class='embed-responsive embed-responsive-16by9'><iframe src='https://player.vimeo.com/video/" + vimeo + "' frameborder='0' webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div></div><div class='col-md-6'><h3>" + videoname + "</h3><small>" + videolength + "</small><p>" + videodesc + "</p></div><hr>";
document.getElementById("container").appendChild(videolisting);
});
});
});
});
I suggest you restructure your database to look like this
users
-cvbnm876567890
- emeil : 'email#email.com'
- name : 'user name'
- pvideos
-fghjk098u6sgs78d80s
-desc : 'description'
-vimeo : 'vimeo_link'
-name : 'name'
-length : 'length'
-category : 'category'
-oiu345ytrdfghj67890
-desc : 'description'
-vimeo : 'vimeo_link'
-name : 'name'
-length : 'length'
-category : 'category'
videos
- videokey1
- category : "Walking Series"
- videokey2
- category : "Running Series"
videos_categories
- Walking Series
- Running Series
You can use db.child('videos').orderByChild('category').equalTo('Walking Series') to get videos in a single category or series. You can modify your query to look like this
var series = db.child('videos_categories').orderByKey();
series.once('value').then(function (snapshot) {
snapshot.forEach(function (childSnapshot) {
var videoseries = childSnapshot.key;
console.log(videoseries);
var category_wrapper = document.createElement('div');
category_wrapper.setAttribute('class', 'row');
category_wrapper.setAttribute('id', videoseries);
document.getElementById("container").appendChild(category_wrapper);
var seriesheading = document.createElement('h3');
seriesheading.textContent = videoseries;
seriesheading.setAttribute('class', 'bg-color-2');
document.getElementById(videoseries).appendChild(seriesheading);
});
}).then(() => {
var videodata = db.child('videos').orderByChild('category');
videodata.once('value').then(function (snapshot) {
snapshot.forEach(function (childSnapshot) {
var videoid = childSnapshot.key;
var vimeo = childSnapshot.child('vimeo').val();
var videoname = childSnapshot.child('name').val();
var videolength = childSnapshot.child('length').val();
var videodesc = childSnapshot.child('desc').val();
var video_category = childSnapshot.child('category').val();
console.log(videoid);
console.log(vimeo);
console.log(videoname);
console.log(videolength);
console.log(videodesc);
var videolisting = document.createElement('div');
videolisting.setAttribute('class', 'row');
videolisting.innerHTML = "<div class='col-md-6'><div class='embed-responsive embed-responsive-16by9'><iframe src='https://player.vimeo.com/video/" + vimeo + "' frameborder='0' webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div></div><div class='col-md-6'><h3>" + videoname + "</h3><small>" + videolength + "</small><p>" + videodesc + "</p></div><hr>";
document.getElementById(video_category).appendChild(videolisting);
});
});
});
Denormalizing your data is important in firebase. So you save the data the way you want it to appear in your view.
You dont need to add every information regarding that video to the user node. Just the details you would need when listing the videos then fetch from the videos node when getting one video
I hope this helps. If you find a better way please share.
#hazelcodes, thank you for the help. Though since it was three weeks ago that I asked for the help, I had already figured it out. Nevertheless, I am grateful. In regards to your statement
"You don't need to add every information regarding that
video to the user node. Just the details you would need when listing
the videos then fetch from the videos node when getting one video."
this is actually what I ended up doing. I completely pulled out 'pvideos' from the user information and made it its own object. I now have three separate object nodes. One for 'users', one for 'videos' and a third for 'pvideos' (videos each user has purchased) like so.
users
abcde (uid)
name: Joe
email: joe#joe.com
...
videos
1234 (videoid)
name: An Awesome Video
...
5678 (videoid)
name: Another Rad Video
...
pvideos
abcde (uid)
5678 (videoid)
orderid: 99999999
In doing it this way, I am able to check which videos the user has purchased from 'pvideos' and show only the information for the matching videoid in 'videos'.
As the user purchases a new video, it is then added as a child of 'pvideos/uid'. If a users uid does not exist as a child of 'pvideos' it is because they have not purchased any videos. Once they purchase their first video the appropriate children are created.
As for the category, I decided that since currently, all videos belong to a single category, I would simply not use the category for now. That was a question I was going to have however when I got to the point of needing additional categories. After your answer here regarding this, I now know how to implement this when the time comes.
I'm trying to build a simple tool that will return a Github profile when you search someone's username. Everything seems to be working, except when I search for a different user, the list of followers from the previous user search don't clear.
For example, a user who has seven followers will suddenly have dozens of follower avatars displaying.
Can anyone tell me how to display the correct number of followers unique to each user when fetching different Github profiles?
var response = null;
var followers = null;
document.getElementsByTagName('button')[0].addEventListener('click', function(r) {
getUser(document.getElementsByTagName('input')[0].value);
});
function getUser(name) {
fetch('https://api.github.com/users/' + name)
.then(function(r) {
console.log(r.status);
return r.json();
})
.then(function(j) {
response = j;
assignValues();
getFollowers(j.followers_url);
});
}
function assignValues() {
document.getElementById('loader').style = 'display: none';
document.getElementById('avatar').src = response.avatar_url;
document.getElementById('name').innerText = response.name;
document.getElementById('username').innerText = response.login;
document.getElementById('location').innerText = response.location;
document.getElementById('bio').innerText = response.bio;
document.getElementById('count').innerText = 'Followers: ' + response.followers;
}
function getFollowers(url) {
fetch(url)
.then(function(r) {
return r.json();
})
.then(function(f) {
followers = f;
listFollowers();
});
}
function listFollowers() {
followers.forEach(function(f) {
var li = document.createElement('li');
li.innerHTML = ''+ '<img src="' + f.avatar_url + '" alt="' + f.login + '"/>'+ '';
document.getElementById('list').appendChild(li);
});
}
You need to clear that #list element in listFollowers function before starting appending new followers to it. For example:
var list = document.getElementById('list');
list.innerHTML = '';
followers.forEach(function(f) {
var li = document.createElement('li');
li.innerHTML = ''+ '<img src="' + f.avatar_url + '" alt="' + f.login + '"/>'+ '';
list.appendChild(li);
});
Three sidenotes here:
why do you use global variables response and followers in your rendering functions when you can pass those as arguments?
as you rerender a 'user profile' first, then wait for avatars' fetch, it's still possible for a user to see the followers of user X when looking for user Y. It's better to clear that section (and show some visual cue for loading data) immediately after the user is switched.
as order of fetch responses is not guaranteed, there's a potential race condition here: if user clicks on that button twice (with different inputs), the earlier input might get back later - and overwrite the former. You need to guard against this, either by storing the latest input value and checking the response, or by some other means.
You can test those by artificially throttling the network speed. And believe me, in real world most of your user will have all sorts of problems with that.
I have a school project, the url is http://angelaalarconcreative.com/LB_v3/
I want to be able to save the user's food choices so that when you click on SAVE it automatically directs you to a different HTML page where the food choices and their combined nutrition facts are compiled together. My teacher gave me this code as a "hint" but I feel more lost than ever staring at her code. Could anyone help me please? :)
$(function() {
$("#save-meal").click(function(){
var authenticated = localStorage.getItem("Greetings");
alert(authenticated);
if(authenticated == null) {
//alert saying you need to login to use this feature
alert("You need to login to use this feature!");
}
else {
var openDiv = "<div> Welcome " + document.write(localStorage.getItem("Welcome"));
var calories = " <div> Calories : " + document.write(localStorage.getItem("calories"));
var totalFat = " <div> Total Fat : " + document.write(localStorage.getItem("totalFat"));
var cholesterol = " <div> Cholesterol : " + document.write(localStorage.getItem("cholesterol"));
var sodium = " <div> Sodium : " + document.write(localStorage.getItem("sodium"));
var dietaryFiber = " <div> Dietary Fiber : " + document.write(localStorage.getItem("dietaryFiber"));
var sugar = " <div> Sugar : " + document.write(localStorage.getItem("sugar"));
var protein = " <div> Protein : " + document.write(localStorage.getItem("protein"));
var closeDiv = "</div>"
}
});
});
I want to know how to use localStorage to get the user's random choices and to retrieve it in a different page. What is the proper syntax for that given the interactivity of my project?
UPDATE: I've changed the JS a little bit according to your answer however it still doesnt work! I suspect faulty syntax. Can someone help me? I feel like I'm so close to getting it!!!!
$(document).ready(function() {
$("#save-meal").click(function(){
var calories = $('.nf__table #value--calories').text();
var totalfat = $('.nf__table #value--total-fat').text();
var cholesterol = $('.nf__table #value--cholesterol').text();
var sodium = $('.nf__table #value--sodium').text();
var fiber = $('.nf__table #value--dietary-fiber').text();
var sugar = $('.nf__table #value--sugar').text();
var protein = $('.nf__table #value--protein').text();
localStorage.setItem('value--calories', calories);
localStorage.setItem('value--total-fat', totalfat);
localStorage.setItem('value--cholesterol', cholesterol);
localStorage.setItem('value--sodium', sodium);
localStorage.setItem('value--fiber', fiber);
localStorage.setItem('value--sugar', sugar);
localStorage.setItem('value--protein', protein);
});
$("#gotosave").click(function(){
document.write(localStorage.getItem('value--calories'));
document.write(localStorage.getItem('value--total-fat'));
document.write(localStorage.getItem('value--cholesterol'));
document.write(localStorage.getItem('value--sodium'));
document.write(localStorage.getItem('value--fiber'));
document.write(localStorage.getItem('value--sugar'));
document.write(localStorage.getItem('value--protein'));
});
});
//document.getElementById("#saved-items").innerHTML = calories;
First of all, welcome to StackOverflow.
You can learn more about localStorage (or sessionStorage) from here. Determine which one is most appropriate for your application.
When your user drags a bunch of food to the 'dinner plate', your .nf__table (nutrition facts table) is updated with a bunch of values. At this point, when your user clicks on the save button, you want your Save event handler to basically grab the values in .nf__table and do a localStorage.setItem() to store the values in local storage.
For example, this is how you would store the amount of calories in localStorage:
var calories = $('.nf__table #value--calories').text();
localStorage.setItem('value--calories', calories);
When the user is directed to the next page, your document-ready handler can then retrieve the stored values using getItem() and update the DOM with those values:
localStorage.getItem('value--calories');
So, the idea is that the nutrition fact values are "remembered" on the first page, so that they can be retrieved on the next page.