Fullcalendar async loading and display of event sources - fullcalendar

I've set up my events sources to pull from two different endpoints. One of these endpoints is heavy and happens to take two seconds longer than the other.
My calendar appears to wait until both sources are loaded before populating the calendar.
Q: is it possible to populate the calendar with the first data source while waiting for the second to finish?
$('#calendar').fullCalendar({
eventSources: [
loadQuickEvents,
loadSlowEvents'
]
});
function loadQuickEvents (start, end, timezone, callback) {
// execute xhr, on success trigger callback
...
callback ()
}
function loadSlowEvents (start, end, timezone, callback) {
// execute xhr, on success trigger callback
...
callback ()
}

Related

How do I force a refresh in google app maker

I have a simple panel that includes a form and a table. All data but one column in the table are entered. The values in the non-entry column are calculated. How do I get the table to refresh itself when after I run a server side script to calculate a new value to show updated table?
If you run your server script from client, then you'll need to use use callback:
google.script.run
.withSuccessHandler(function() {
app.datasources.MyDatasource.load();
})
.withFailureHandler(function() {
// TODO: handle error
})
.myServerScript();
In case your server script is executed by some schedule (trigger) or by other users then you'll need to reload table's datasource from time to time:
// Page onAttach event handler
var interval = setInterval(function() {
app.datasources.MyDatasource.load();
}, 3000);
// Page onDetach event handler
clearInterval(interval);

how to call fullcalendar events() with a paremeter?

Is there a way to filter events based on a drop down?
I tried :
events: '/Controller/action?id='+id,
$("#drop").change(function () {
id = $('#drop').val();
$('#calendar').fullCalendar('refetchEvents');
But the controller does not see the new id.
Any suggestions on passing a paremter to the events() method?
You gave the result of '/Controller/action?id='+id to the calendar as the events feed when the calendar was initialised. e.g. you passed in /Controller/action?id=3, for example. That code has run and does not run again. fullCalendar stores that static string as the URL of the events feed. It doesn't pay any attention to the value of "id" later.
The simplest way to solve this is probably using a custom event feed, as per https://fullcalendar.io/docs/event_data/events_function/ :
//declare the calendar with a custom "events" functions
$("#calendar").calendar({
//..all your calendar options, and then the events:
events: function( start, end, timezone, callback ) {
$.ajax({
//whatever ajax parameters you need, but make sure:
url: /Controller/action,
data: { "id": $('#drop').val(), "start": start.format("YYYY-MM-DD"), "end": end.format("YYYY-MM-DD") }
});
}
});
$("#drop").change(function () {
$('#calendar').fullCalendar('refetchEvents');
});
That way, when "refetchEvents" is called, it runs the function that you passed as the "events" parameter, which can look up the value of the dropdown dynamically at that moment in time.
Note I've also added "start" and "end" parameters to your data, because your event source is supposed to filter the events returned by the dates actually being displayed on the calendar, otherwise you end up returning all events every time the view or date changes.

How to get all subscription data before rendering and then just update the dom when new data is received?

I currently havea widget which grabs hundreds of documents from the DB via subscription and then keep listening for new documents, so it can update a stock chart.
There is a problem tough, which is every time the data is updated the chart is updated, which causes a redraw.
This is a problem cause it's calling redraw hundreds of time at the beginning even tough it just need to "fetch all data then draw and wait for updates", the updates will then happen not very often, so then it would be ok to redraw.
my current code:
Template.nwidget.onRendered(function() {
return this.autorun(function() {
var data;
data = {};
data = Data.find({
type: 'my_type'
});
data = data.fetch();
return update(data);
});
});
For doing some after data subscription you can do like this:
Meteor.subscribe( 'collection', {
onStop: function( error /* optional */ ) {
// when the sub terminates for any reason,
// with an error argument if an error triggered the stop
},
onReady: function() {
// when ready
}
});
If you want to render page after the data subcribe then you can add waitOn in your router.
There is one more way to check where subscription is ready or not. If subscription is not ready you can show something else like a loading screen.
var handle = Meteor.subscribe( 'collection');
Tracker.autorun(function() {
if (handle.ready())
//write whatever you want to do here.
});
For the auto update in your view you can store the date in a reactive thing its may reactive var, Session or collection.
Then you can return there values from helper to view. And that will auto update your view.

TypeError: callback is not a function

I am just adding the events to calendar.
============This is my Code============
events: function (start, end , callback) {
var events = [];
calEvents=Events.find();
calEvents.forEach(function(evt){
events.push({
id:evt._id,
title:evt.title,
start:evt.date,
});
});
console.log(events);
callback(events);
},
But in console, I am getting this Error And None of events showing on calendar.
TypeError: callback is not a function
If you look at the docs for FullCalendar, you can see that it's expecting a third argument before the callback: timezone.
function( start, end, timezone, callback ) { }
Therefore right now, your code is using the timezone (which you named callback) as a function, and it doesn't like that very much. Just add timezone in your code as shown above, and your callback should work.

Meteor How to block a method call before the first one is finished?

I have the following scenario:
Client side has a button clicking it will execute Meteor.call method on the server-side which will call API and fetch products, During this time I wan't to disable this button + block this method from executing again basically nothing stops you from clicking the button 100x times and server will keep on executing same method again and again.
Few ideas I had in my mind: Use sessions to disable button (Problem: can still using the console Meteor.call and abuse it)
I also looked at Meteor.apply in the docs with wait:true didn't seems to stop from method execution. I honestly not sure how this kind of thing is handled with no hacks.
Client-side:
'click .button-products': function(e){
Meteor.call('getActiveProducts', function(error, results){
if (error)
return Alerts.add(error.reason, 'danger', {autoHide: 5000});
if (results.success)
return Alerts.add('Finished Importing Products Successfully', 'success', {autoHide: 5000});
})
}
Server-side
Meteor.methods({
getActiveProducts: function(){
var user = Meteor.user();
var api = api.forUser(user);
importProducts = function(items){
nextPage = items.pagination.next_page;
items.results.forEach(function(product){
var sameproduct = apiProducts.findOne({listing_id: product.listing_id});
if (sameproduct) {
return;
}
var productExtend = _.extend(product, {userId: Meteor.userId()});
apiProducts.insert(productExtend);
});
};
var products = api.ProductsActive('GET', {includes: 'Images', limit: 1});
importProducts(products);
while (nextPage !== null) {
products = api.ProductsActive('GET', {includes: 'Images', page: nextPage, limit: 1});
importProducts(products);
}
return {success: true};
}
});
From the Meteor docs:
On the server, methods from a given client run one at a time. The N+1th invocation from a client won't start until the Nth invocation returns. However, you can change this by calling this.unblock. This will allow the N+1th invocation to start running in a new fiber.
What this means is that subsequent calls to the method won't actually know that they were made while the first call was still running, because the first call will have already finished running. But you could do something like this:
Meteor.methods({
getActiveProducts: function() {
var currentUser = Meteor.users.findOne(this.userId);
if (currentUser && !currentUser.gettingProducts) {
Meteor.users.update(this.userId, {$set: {gettingProducts: true}});
// let the other calls run, but now they won't get past the if block
this.unblock();
// do your actual method stuff here
Meteor.users.update(this.userId, {$set: {gettingProducts: false}});
}
}
});
Now subsequent calls may run while the first is still running, but they won't run anything inside the if block. Theoretically, if the user sends enough calls, the first call could finish before all of the others have started. But this should at least significantly limit the number of etsy calls that can be initiated by a user. You could adapt this technique to be more robust, such as storing the last time a successful call was initiated and making sure X seconds have passed, or storing the number of times the method has been called in the last hour and limiting that number, etc.
A package I wrote a while back might come in handy for you. Essentially it exposes the Session api on the server side (hence the name), meaning you can do something like ServerSession.set('doingSomethingImportant', true) within the call, and then check this session's value in subsequent calls. The session can only be set on the server, and expires upon connection close (so they could spam calls, but only as fast as they can refresh the page).
In the event of error, you can just reset the session. There shouldn't be any issues related to unexpected errors either because the session will just expire upon connection close. Let me know what you think :)

Resources