Data duplicates whenever its onclick link is clicked - firebase

So I have a table in html which displays all rentals from my database. The owner name and renter is retrieve from two different queries which is done inside the uery of retrieving data from rental table on database. The The problem is whenever I click the link that enables the function rentalhistory to run, data was added again resulting to duplicate the previous data.
var rentalref = db.ref('rental');
rentalref.once("value").then(function(snapshot) {
var history = [];
snapshot.forEach(function(childSnapshot) {
var key = childSnapshot.key; // "ada"
var childData = childSnapshot.val();
console.log(childSnapshot.key);
childSnapshot.forEach(function(data) {
var pid = data.val().property_id;
var rid = data.val().renter_id;
var oid = data.val().owner_id;
var date = data.val().date_created;
var userref = db.ref('users/');
userref.orderByChild("user_id").equalTo(rid).once("child_added", function(dataa) {
console.log(dataa.val().username);
var rname = dataa.val().username;
var userref = db.ref('users/');
userref.orderByChild("user_id").equalTo(oid).once("child_added", function(dataa2) {
var oname = dataa2.val().username;
$("#rentaltable").append("<tr><td>" +pid+"</td><td>" +oname+"</td><td>" +rname+"</td><td>" +date+"</td></tr>");
});
});
});
});
});

Related

How to disable automatically signin after create new user in Firebase?

The admin can only add a new user. My problem is when I created a new user, it automatically signin that user then it signouts the admin.
FYI. I didn't use the Admin SDK. Firebase
My code:
var password = $('#row' + x + 'cell1').val();
var fname = $('#row' + x + 'cell2').val();
var email = teacherID + "#gmail.com";
console.log(email + password);
firebase.auth().createUserWithEmailAndPassword(email, password).then(function(user) {
//Add to users table
var pushedUser = firebase.database().ref('users/' + user.uid).set({ role: "Teacher",
fullname: fname });
//Add name and default dp to the Authorization table
user.updateProfile({
displayName: fname,
photoURL: "default_dp",
});
var $rowFirst = $("table:first").find("tr:first");
var $rowNext = $('#tblCSVaccounts tr').eq(x);
//get all td's in row
var $tdsFirst = $rowFirst.find("td");
// loop all td
$.each($tdsFirst, function(i, el) {
//get value of each td
var txtEntity = $(this).find("input").val();
var $rowNext = $('#tblCSVaccounts tr').eq(x);
var $tdsNext = $rowNext.find("td:eq(" + i + ")");
$.each($tdsNext, function(i, el) {
//get value of each td
var txtValue = $(this).find("input").val();
//Update in database
const mySection = $('#sectionUpload').val();
var pushedRef = firebase.database().ref('Teachers/' + user.uid).update({ [txtEntity]: txtValue });
$('#alert-success').removeClass('hide');
});
});
}, function(error) {
// An error happened.
var errorCode = error.code;
var errorMessage = error.message;
});
you can use firebase.auth().onAuthStateChanged(...)
hope its help you, guy!

Firebase Request Timeout Feature [duplicate]

I'm trying to create a cloud function for firebase that remove a user depending on the delay value and insert back the after the number of delay.
exports.delayqueue = functions.database.ref('/queues/{queueid}/members/{memberid}').onWrite(event => {
var members = event.data.ref.parent;
var user = event.data;
var queueid = members.parent;
var userid = event.params.memberid;
var delayfor = user.child('delay').val();
var name = user.child('name').val();
if(delayfor != 0){
members.child(event.params.memberid).remove();
join(userid,queueid,delayfor,name);
return;
}else{
return;
}
});
function join(userid,queueid,delayfor,name){
setTimeout(function(){
var ref = db.ref("queues/queueid/members/userid");
ref.set({
name: name,
timestamp: Date.now(),
delay : 0
});
}, delayfor*1000);
};
But it's not working can someone help?
You'll need to wrap your setTimeout in a Promise:
exports.delayqueue = functions.database.ref('/queues/{queueid}/members/{memberid}').onWrite(event => {
var members = event.data.ref.parent;
var user = event.data;
var queueid = members.parent;
var userid = event.params.memberid;
var delayfor = user.child('delay').val();
var name = user.child('name').val();
if (delayfor !== 0){
members.child(event.params.memberid).remove();
return join(userid,queueid,delayfor,name);
} else {
return;
}
});
function join(userid,queueid,delayfor,name){
return new Promise((resolve, reject) => {
setTimeout(function(){
var ref = db.ref("queues/queueid/members/userid");
ref.set({
name: name,
timestamp: Date.now(),
delay : 0
}).then(resolve, reject);
}, delayfor*1000);
});
};
Note that the time spent waiting for setTimeout is billed as function execution time and is also subject to the function timeout. If you're only delaying a few seconds, that might be okay, but if the delay is expected to be minutes this solution isn't going to be viable or cost-effective.

Firebase return multiple objects

I am using firebase and in below query extand() is a function that concatenate the objects. Can some one help me to remove $timeout from my query ?
currently i am waiting for my playerList to fill.
var getJoinedPlayers = function(gameId){
var deferred = $q.defer();
var playerList = {};
var usersRef = new Firebase(FBURL+'users');
var gameRef = new Firebase(self.firebaseURL);
var gamePlayersRef = gameRef.child(gameId).child("players");
gamePlayersRef.on("child_added", function(snap) {
usersRef.child(snap.key()).once("value", function(data) {
playerList[snap.key()] = extend({'playerId': snap.key()},data.val());
})
});
$timeout(function() {
if (playerList) {
deferred.resolve(playerList);
} else {
reason = {'message': "player Not found"};
deferred.reject(reason);
}
}, 1300);
return deferred.promise;
};
I would simplify this by replacing "child_added" with "value". This will return the list of players, which you could iterate over with regular JS.
Then call
usersRef.child(snap.key()).once("value", function(data)
for each of of the items in the result, and push each of these promises into an array
promiseArray.push(usersRef.child(snap.key()).once("value", function(data)...
then you could
$q.all(promiseArray).then(...
that will combine all promises into a single promise

Here Map API, map rendering fails

Ive successfully created a map, marker and infobubble that uses values from reverse geocoding method. With 1 location, the map works fine and displays the marker and info bubble accordingly. However when i pass two location values from the backend (i am using jsp) the map does not render.
Functions I use are: addMarkerToGroup, addInfoBubble, onSuccess,
function addMarkerToGroup(group, position, inf){
var marker = new H.map.Marker(position);
//add custom data to marker
marker.setData(inf);
group.addObject(marker);
}
function addInfoBubble(position,inf){
var group = set_map.group;
var map = set_map.map;
var ui = set_map.ui;
map.addObject(group);
//add 'tap' event listener, that opens info bubble, to the group
group.addEventListener('tap', function(evt){
//event target is the marker itself, group is a parent event target
var bubble = new H.ui.InfoBubble(evt.target.getPosition(),{
// read custom data
content: evt.target.getData()
});
//show info bubble
ui.addBubble(bubble);
}, false);
addMarkerToGroup(group,position,inf);
}
function callback(){
var platform = new H.service.Platform({
app_id: '#',
app_code: '#',
useCIT: true,
useHTTPS: true
});
var defaultLayers = platform.createDefaultLayers();
var obj = your_location.map_obj;
var map = new H.Map(
obj,
defaultLayers.normal.map,
{
zoom:your_location.map_zoom,
center: {lat:your_location.latitude,lng:your_location.longitude}
});
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
var ui = H.ui.UI.createDefault(map, defaultLayers);
var group = new H.map.Group();
}
function onSuccess(result){
var index = your.count;
var myclt = your.get_yours(index);
var myttl = your.get_title(index);
var myinf = your.get_info(index);
var location = result.Response.View[0].Result[0];
var countryName, countryCode, province, city, zipcode;
countryName = location.Location.Address.Country;
countryCode = location.Location.Address.Country;
province = location.Location.Address.State;
zipcode = location.Location.Address.PostalCode;
city = location.Location.Address.City;
var address = "";
if (city && city != "") {
address = city;
}
if (province && province != "") {
if (address && address != "") {
address += ", " + province;
} else {
address = province;
}
}
if (zipcode && zipcode != "") {
if (address && address != "") {
address += ", " + zipcode;
} else {
address = zipcode;
}
}
if (countryName && countryName != "") {
if (address && address != "") {
address += ", " + countryName;
} else {
address = countryName;
}
}
$.ajax({
url: "view_remote_device_control.do",
data: {
mode: "update",
client_id: myclt,
city: city,
province: province,
zipcode: zipcode,
country: countryCode
},
type: "GET",
cache: false,
async: true
});
myttl += address;
var position = new H.geo.Point(location.Location.DisplayPosition.Latitude,location.Location.DisplayPosition.Longitude);
var inf = {content: location.Location.Address.Label};
var myinfo = inf.content;
addInfoBubble(here_maps_callback.map,position,inf.content,here_maps_callback.ui);
return myinf;
};
While debugging I get the error:
Uncaught InvalidArgumentError: H.map.ViewModel#setCameraData (Argument #0 position)
Okay, so i realized that it the reason why it was not rendering was due to:
center: {lat:your_location.latitude,lng:your_location.longitude}
Basically due to passing two location values, the location array had two values for both latitude and longitude and it did not know which to use to set the center. By changing both the values of lat and lng to 0 and using:
map.setCenter(evt.target.getPosition());
inside the group event listener it rendered the map accordingly.
Hope this is helpful
A bit confused how is the callback is happening, where are the two location finally retrieved on the JavaScript side ? Do you face the issue if you directly pass the locations in javascript , i mean hard coded as a test ?

Meteor client-side transform collections with external data (youtube)

I'm working on a multi-tenant apps. Each app will have a video module which takes several youtube playlists/channels id as input.
Apps = {_id: "app01", playlists:['PL4IrNZLvgtED4RTH3xCf9085hwqKmb4lM','PLlYqpJ9JE-J8QIlua0KsBIxp-VQLyM_nO']}
Apps = {_id: "app02", playlists:['id22','id23']}
and so on.
When user redirect to address localhost:3000/app/:_id, the app subscribe to Meteor.subscribe('apps',_id).
Now on the client side, i need to render a page that shows a list of playlists (or list of channels) with playlist's name, playlist thumbnail; and then if user clicks on the name/thumbnail, it displays another page with a list of videos belongs to that playlist/channel.
What i am doing is to have a helper to retrieve all youtube playlists's info:
Template.Videos.helpers({
myPlaylist:function(){
return Apps.findOne({}, {
transform: function (doc){
playlists = doc.playlists;
doc.date = new Date(); //for testing
doc.videos = [];
for (var i=0;i<playlists.length;i++){
console.log('find playlist: ',playlists[i]);
var url = 'https://gdata.youtube.com/feeds/api/playlists/'+playlists[i]+'?v=2&alt=json';
$.getJSON(url, function(response){
var video={};
video._id = response.feed.yt$playlistId.$t;
video.title = response.feed.title;
video.entry = response.feed.entry;
videos.push(video);
})//end getJSON
}//end for
doc.videos = videos;
console.log('Result:', doc);
return doc;
}
});
}
});
The problem is in my template, I can see myPlaylist.date as a result of transform, but I cannot see myPlaylist.videos (although I see the console.log result has data)
Does anyone has an idea how to solve this? Very appreciate!
As #Ian Jones commented, $.getJSON is asynchronous so doc.videos will never have a value where you’ve put your console.log. To solve this, use the ReactiveVar package:
Template.Videos.onCreated(function() {
this.videos = new ReactiveVar([]);
var self = this;
Apps.findOne({}, {
transform: function (doc){
playlists = doc.playlists;
for (var i=0;i<playlists.length;i++){
console.log('find playlist: ',playlists[i]);
var url = 'https://gdata.youtube.com/feeds/api/playlists/'+playlists[i]+'?v=2&alt=json';
$.getJSON(url, function(response){
var video={};
video._id = response.feed.yt$playlistId.$t;
video.title = response.feed.title;
video.entry = response.feed.entry;
var videos = self.videos.get();
videos.push(video);
self.videos.set(videos);
})//end getJSON
}//end for
}
});
}
});
Template.Videos.helpers({
myPlaylist:function(){
var instance = Template.instance();
return instance.videos.get();
}
});
Thanks for all your helps. I was unwilling to do reactive-var from the beginning, but your answer motivated me to go for it, big thanks.
This is my final code:
Template.Videos.created = function(){
var instance = this;
instance.videos = new ReactiveVar([]);
instance.autorun(function(){
MenusList.findOne({}, {
transform: function (doc){
playlists = doc.playlists;
for (var i=0;i<playlists.length;i++){
console.log('find playlist: ',playlists[i]);
var url = 'https://gdata.youtube.com/feeds/api/playlists/'+playlists[i]+'?v=2&alt=json';
$.getJSON(url, function(response){
var video={};
video._id = response.feed.yt$playlistId.$t;
video.title = response.feed.title;
video.entry = response.feed.entry;
var videos = instance.videos.get();
videos.push(video);
instance.videos.set(videos);
})//end getJSON
}//end for
return doc;
}//end transform
});//end findOne
});//end autorun
}
Template.Videos.helpers({
myPlaylist:function(){
var instance = Template.instance();
return instance.videos.get();
}
});

Resources