Passing the name of a function as the eventMouseover callback - fullcalendar

I'm trying to pass the actual name of a function rather than an anonymous function to my FullCalendar initialization like so:
$('#gcally_calendar').fullCalendar({
"eventSources":
[...],
"eventMouseover":"fc_hover_in"
});
I'm getting a console error when I do this, however: Uncaught TypeError: Array.prototype.slice.call is not a function.
Any thoughts on this?
For thoroughness, this is the function:
function fc_hover_in(calEvent, jsEvent, view) {
var tooltip = '<div class="tooltipevent" style="width:100px;height:100px;background:#ccc;position:absolute;z-index:10001;">' + calEvent.title + '</div>';
jQuery("body").append(tooltip);
jQuery(this).mouseover(function(e) {
$(this).css('z-index', 10000);
$('.tooltipevent').fadeIn('500');
$('.tooltipevent').fadeTo('10', 1.9);
}).mousemove(function(e) {
$('.tooltipevent').css('top', e.pageY + 10);
$('.tooltipevent').css('left', e.pageX + 20);
});
}
But it's not even being called at this point.

You should remove the quotes to pass the function as a reference.
This:
"eventMouseover":"fc_hover_in"
Becomes this:
"eventMouseover": fc_hover_in

Related

Why doesn't my query NOT recognize my valid variable?

Help! Something very strange is happening within my app.
I have a merchantReview template that is supposed to show the number of reviewers.
Below is what the template looks like:
<template name="merchantReview">
<div> {{numberOfReviewers}} Total</div>
And what the helper code looks like:
Template.merchantReview.helpers({
'numberOfReviewers': function () {
var numberOfReviewers = 0;
var merchantProfileId = Session.get('offerUserId2');
console.log("The numberOfReviews _id session is: " + merchantProfileId );
merchantReviews.find({_id: merchantProfileId}).map(function (doc)
{
numberOfReviewers += doc.noOfReviewers;
});
return numberOfReviewers;
}
});
This yields nothing on the merchantReview page at all.
Lets have a look at the Router:
Router.route('/merchantReview/:_id', {
template: 'merchantReview',
data: function(){
},
waitOn: function(){
return Meteor.subscribe('merchantReviews');
}
});
And what am subscribing to:
Meteor.publish('merchantReviews', function publishmerchantReviews(){
return merchantReviews.find();
});
Now for the "Something very strange" part.
When I run this following code (which is similar to the helper code) in the chrome browser console, I get mixed results.
When I run the below:
var numberOfReviewers = 0;
var merchantProfileId = Session.get('offerUserId2');
console.log("The _id is: " + merchantProfileId );
merchantReviews.find({_id: merchantProfileId}).map(function (doc)
{
numberOfReviewers += doc.noOfReviewers;
});
console.log (numberOfReviewers);
...it yields:
The _id is: udEnfEmy5DSBvDsSy
0
As you see, it bypasses the merchantReviews.find query.
However when slightly alter the code, and run:
var numberOfReviewers = 0;
var merchantProfileId = Session.get('offerUserId2');
console.log("The _id is: " + merchantProfileId );
merchantReviews.find({_id: "udEnfEmy5DSBvDsSy"}).map(function (doc)
{
numberOfReviewers += doc.noOfReviewers;
});
console.log (numberOfReviewers);
This time it yields:
The _id is: udEnfEmy5DSBvDsSy
93
Strange isn't it?
Can anyone explain why the
merchantReviews.find({_id: merchantProfileId})... query doesn't recognize the merchantProfileId variable which holds the udEnfEmy5DSBvDsSy value? And how do I fix this?
The reason why the variable wasn't being recognized in the query is because the variable was in array form instead of string form.
I realized this by console.log("The _id is: " + merchantProfileId );
This would sometimes yield:
["udEnfEmy5DSBvDsSy"]
I resolved his by sanitizing the variable to ensure its a string not an array using the toString() function. So in code its : merchantProfileId.toString();
Following is the full resolution in code:
var numberOfReviewers = 0;
var merchantProfileId = Session.get('offerUserId2');
// Below immediately sanitize the variable ensuring it is a string
// before its used in the query.
merchantProfileId = merchantProfileId.toString();
console.log("The _id is: " + merchantProfileId );
merchantReviews.find({_id: merchantProfileId}).map(function (doc)
{
numberOfReviewers += doc.noOfReviewers;
});
console.log (numberOfReviewers);
This yields:
The _id is: udEnfEmy5DSBvDsSy
104
You can simplify and speed up your helper by just using .count() on the cursor. If, as you mentioned in the comments, your offerUserId2 session variable returns an array then you can just reference its first element with [0]:
Template.merchantReview.helpers({
numberOfReviewers() {
return merchantReviews.find(Session.get('offerUserId2')[0]).count();
}
})
Your problem is a classic javascript async gotcha. Looking at your code,
merchantReviews.find({_id: "udEnfEmy5DSBvDsSy"}).map(function (doc)
{
numberOfReviewers += doc.noOfReviewers;
});
console.log (numberOfReviewers);
The adding to numberOfReviewers happens in the callback for merchantReviews.find() - which usually happens at some later time. Your console.log likely happens before that, which explains why you get wierd results. If you change your code to this, you will get consistent results.
merchantReviews.find({_id: "udEnfEmy5DSBvDsSy"}).map(function (doc)
{
numberOfReviewers += doc.noOfReviewers;
console.log (numberOfReviewers);
});
Think of it this way, in javascript time moves to the right, not down the page. So indented code that is part of a callback (and indented to the right) happens after the code at the bottom.

Meteor template autorun (Session variable)

Imagine I have a session variable that holds an image source. Every second, I want to the helper that contains this session to run.
if (Meteor.isClient) {
Template.TargetTask.helpers({
'imageSrc': function (e, template) {
var clock = setTimeout(function() {
var position = IMAGE_POOL.pop();
Session.set("currentTarget", position);
}, 1000);
var position = Session.get("currentTarget");
var imageSrc = '/' + position + '.bmp';
return imageSrc;
}
});
the image sources are coming from a global IMAGE_POOL. However, it is possible that the pool contains two same images consecutively. In this case, Session.set() will be called with the same argument and the session will remain unchanged.
Q1. When Session variable remains unchanged, does the template helper not autorun even if Session.set() is called?
Q2. If so, how should I make it run every time a new image is popped?
No, Tracker computations are not invalidated if the value doesn't change.
Session.set('test', false);
Tracker.autorun(function() { console.log(Session.get('test')) }); //Logs 'false'
Session.set('test', false); //Nothing
Session.set('test', true); //Logs true
In your case, if you want to preserve this code structure (which seems a bit heavy to me) you could instead store an object with a timestamp:
if (Meteor.isClient) {
Template.TargetTask.helpers({
'imageSrc': function (e, template) {
var clock = setTimeout(function() {
var position = IMAGE_POOL.pop();
Session.set("currentTarget", {
position : position,
timestamp : Date.now()
});
}, 1000);
var position = Session.get("currentTarget").position;
var imageSrc = '/' + position + '.bmp';
return imageSrc;
}
});
}

Opening link in javascript widget in new window

I get the following error with this code in the update function below and I don't understand why.
err: [RangeError: Maximum call stack size exceeded]
Does it have something to do with using Meteor.setTimeout()?
if (Meteor.isServer) {
Meteor.clearTimeout(league.nextPickTimeoutId);
var pickTimeoutId = Meteor.setTimeout(function () {
Meteor.call('pickPlayer', leagueId, findTopScoringPlayer(leagueId, nextTeam._id)._id);
}, 30*1000);
Leagues.update(leagueId, {
$set: {
nextPickTill: new Date().getTime() + (league.secondsPerPick * 1000),
nextPickTimeoutId: pickTimeoutId
}
}, function (err) {
if (err) console.log('err:', err);
});
}
The problem was that:
Meteor.setTimeout() returns a handle that can be used by Meteor.clearTimeout. Source
The Meteor.clearTimeout() function confused me that I thought took an id as an argument.

Async call generates " Error: Can't wait without a "fiber", even with _wrapAsync

I've been having a problem using an RSS parser in meteor. It's an async call, so it needs ot be wrapped, however it still doesn't seem to work. I presume this is because the anonymous on('readable' function is outside the fiber, but I can't see how to resolve it.
var FeedParser = Meteor.require('feedparser');
var request = Meteor.require('request');
function getBlog(url, parameter, id){
request(parameter)
.on('error', function (error) {
console.error(error);
})
.pipe(new FeedParser())
.on('error', function (error) {
console.error(error);
})
.on('readable', function () {
var stream = this,
item;
while (item = stream.read()) {
Items.insert(new_item);
}
});
}
var wrappedGetBlog = Meteor._wrapAsync(getBlog);
Meteor.methods({
blog: function (url, parameter, id) {
console.log('parsing blog');
var items = wrappedGetBlog(url, parameter, id);
}
});
Meteor._wrapAsync() expects the wrapped function to return error and result to a callback. Your function, getBlog(), does not do that so _wrapAsync is not the right approach.
I have wrapped that function before but used a Future.
That approach allowed me to call feedparser from a Meteor.method(), which doesn't allow async functions, but you are also trying to do an insert inside the readable event. I think that insert will complain if it is not in a fiber. Maybe like this would also be necessary:
var r = request( parameter );
r.on( 'response' , function(){
var fp = r.pipe( new FeedParser() ); //need feedparser object as variable to pass to bindEnvironment
fp.on('readable', Meteor.bindEnvironment(
function () {
var stream = this,
item;
while (item = stream.read()) {
Items.insert(new_item);
}
}
, function( error ){ console.log( error );}
, fp // variable applied as `this` inside call of first function
));
});
Fibers is another option...
var Fiber = Npm.require( "fibers" );
.on('readable', function () {
var stream = this,
item;
while (item = stream.read()) {
Fiber( function(){
Items.insert(new_item);
Fiber.yield();
}).run();
}
});

Scope problem with SetTimeOut

I don't know why but this code is not working ? Why would it not ? I guess it is because scope problem I am having here :
function washAway(obj) {
alert($(obj)); // says HTML Object which is fine
setTimeout(function() {
alert($(obj)); // says undefined
$(obj).fadeOut("slow", function() {
$(this).remove();
});
}, 2000);
};
At the point where the function in the timeout executes, it has no way to know what obj is - it was a parameter passed into the method where the timeout was set up, but the function inside has no reference to it.
An alternative approach is to write a jQuery plugin to wait before it acts like this:
function($){ //to protect $ from noConflict()
$.fn.pause = function(duration) {
$(this).animate({ dummy: 1 }, duration);
return this;
};
}
Then you can use:
$(obj).pause(2000).fadeOut("slow", function() { $(this).remove(); });
Any ways, I've found my answer after a couple of try/wrong. But I am still wondering why it didn't work out.
Here is the code :
function washAway(obj) {
alert($(obj).attr("id"));
var a = function() {
var _obj = obj;
return function() {
$(_obj).fadeOut("slow", function() {
$(this).remove();
});
};
};
setTimeout(a(), 2000);
};
Edit : I think I understood the problem here :
Because we are talking about closures here, when washAway execution finishes, the variable obj is destroyed so setTimeOut function callback function can't use that resource because it is no more available on the stack and it is not also a global variable.

Resources