Firebase trigger on current time - firebase

I create something like calendar with events.
I want to popup message for user when the event come up.
My solution:
//this code runs in loop
var offsetRef = new Firebase("https://example.firebaseio-demo.com/.info/serverTimeOffset");
offsetRef.on("value", function(snap) {
var offset = snap.val();
var estimatedServerTimeMs = new Date().getTime() + offset;
fbRef.endAt(estimatedServerTimeMs).once("value", function(ss) {/*remove old events*/});
});
Is´t possible something like this (without loop)?
fbRef.endAt(Firebase.ServerValue.TIMESTAMP).on("child_added", function(snap) {/*...*/});
Thank you for reply

It's best to calculate the serverTimeOffset just once, and then wrap the popup in a setTimeout after you know what the current time (approximately) is:
var timeouts = [];
offsetRef.on("value", function(snap) {
// Cancel all previous timeouts.
timeouts.forEach(function(i) { clearTimeout(i); });
var estTime = new Date().getTime() + snap.val();
var promptTime = /* Get time at which you want to prompt */
timeouts.push(setTimeout(function showPrompt() {
...
}, promptTime));
});

Related

Firestore update document on beforeunload

How can I update a document in Firestore on beforeunload?
function sleep() {
var start = new Date().getTime();
while (new Date().getTime() < start + 3000);
}
window.addEventListener("beforeunload", function(event) {
const ref = db.collection('users').doc(currentUser.uid);
ref.update({
profiles: true
}).then(function() {
console.log("Added!");
});
console.log("Blocking for 3 seconds...");
sleep();
console.log("Done!!");
});
Seems like ref.update() is never called? Any idea why that's the case?

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();
}
});

Durandal refresh() function not working?

I'm trying to detect when the user hits "refresh" from my app to load some data.
I have this:
var refresh = function() {
alert('refresh');
};
var vm = {
refresh: refresh,
data: ko.observable()
};
However I never get the alert in my browser, and a breakpoint set at the opening of the function does not get hit when I refresh the page from this view. How can I properly use the refresh function?
I would suggest hooking into the canDeactivate method in your view model.
var refresh = function() {
alert('refresh');
};
var canDeactivate = function(isClose){
if (isClose)
{
refresh();
return false;
}
else return true;
};
var vm = {
data: ko.observable(),
canDeactivate: canDeactivate
};

Google Maps APIV3 listener set_at not firing until second time

I have the following code, which should trigger an alert when a Polygon shape is changed. This alert only appears after the shape has been changed twice. Meaning, I have to resize the shape two times before the event is triggered.
Any idea as to what may be causing this behavior?
function drawListener(drawingManager) {
var coord_listener = google.maps.event.addListener(drawingManager, 'polygoncomplete', function (polygon) {
var coordinates = (polygon.getPath().getArray()); //get
var bounds = new google.maps.LatLngBounds();
var people = [];
google.maps.event.addListener(polygon.getPath(), 'set_at', function () { //check to see if the item has been changed //THIS ONLY GETS CALLED AFTER POLYGON HAS BEEN CHANGED TWICE
alert('changed');
});
});
I found my answer: I must use 'insert_at' in addition to 'set_at'
google.maps.event.addListener(polygon.getPath(), 'set_at', function () {
alert('changed');
});
google.maps.event.addListener(polygon.getPath(), 'insert_at', function () {
alert('also changed');
});
Thanks.

Google Places API autocomplete not working

Right now, the autocomplete box works just fine when I click on the location, but when I press down, highlight the location that I want to go to, and press enter, it simply goes back to the home location of the map. Any insights on this? I call this function in initialize(). I'm lost as to what I possibly did wrong. Is this just a google api bug? If so, any insights as to how to work around it?
function setupAutoComplete() {
var defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(-90, -180),
new google.maps.LatLng(90, 180));
var input = document.getElementById('placeSearch');
var options = {
bounds: defaultBounds,
types: ['(regions)']
};
autocomplete = new google.maps.places.Autocomplete(input, options);
google.maps.event.addListener(autocomplete, 'place_changed', function() {
alert('hi');
removeAllOverlays();
var place = autocomplete.getPlace();
var mapCenter = place.geometry.location;
var colLat = mapCenter.lat() - (halfPoints)*latSeparation;
var colLng = mapCenter.lng() - (halfPoints)*lngSeparation;
var tempStart = new google.maps.LatLng(colLat, colLng);
map.setCenter(mapCenter);
pointArray[0][0] = tempStart;
reService();
mapSearch();
drawBounds();
});
}
Thanks so much!
I guess the input#placeSearch is placed inside a <form>.
You submit the form when you press [ENTER].
You may either remove the surrounding form or cancel the submission by adding:
onsubmit="return false"
...to the form-element.
I just hit this issue and went with the following, as I do want to submit the form at a later stage. This code is from google groups.
var input = document.getElementById('create-location');
var options = {
//types: ['(cities)'],
};
autocomplete = new google.maps.places.Autocomplete(input, options);
google.maps.event.addDomListener(input, 'keydown', function(e) {
if (e.keyCode == 13)
{
if (e.preventDefault)
{
e.preventDefault();
}
else
{
// Since the google event handler framework does not handle early IE versions, we have to do it by our self. :-(
e.cancelBubble = true;
e.returnValue = false;
}
}
});

Resources