Randomly occurs with Meteor: "TypeError: Cannot read property 'invalidate' of undefined" - meteor

On what seems to be random occasions, when a user on my website tries to answer a question on the quiz page, the following error occurs:
TypeError: Cannot read property 'invalidate' of undefined
at Tracker.Dependency.changed (tracker.js:388)
at ReactiveVar.set (reactive-var.js:82)
at null. (builtins.js:22)
at view.js:191
at Function.Template._withTemplateInstanceFunc (template.js:437)
at view.js:190
at Object.Blaze._withCurrentView (view.js:523)
at viewAutorun (view.js:189)
at Tracker.Computation._compute (tracker.js:294)
at Tracker.Computation._recompute (tracker.js:313)
I am unsure as to why this occurs, and I am not entirely sure when this error even means so if someone could point me in the right direction, that would be great!
Note: this error seems to only occur when using Chrome.

I'll hazard a guess, here's the culprit code in Tracker.Dependency
Tracker.Dependency.prototype.changed = function () {
var self = this;
for (var id in self._dependentsById)
// My Comment - we're expecting this to be a `Tracker.Computation` which has an `.invalidate()` method!
self._dependentsById[id].invalidate();
};
So, the problem is that something is modifying Object.prototype.
eg.
Object.prototype.test = function(){}
var emptyObj = {};
for (i in emptyObj)
console.log('has key=', i, 'isOwnProperty?=', emptyObj.hasOwnProperty(i))
will print out:
has key= test isOwnProperty?= false
A possible solution to try, would be adding this snipped to the client, and seeing if it fixes the problem (At least temporarily):
Tracker.Dependency.prototype.changed = function () {
var self = this;
for (var id in self._dependentsById){
if (self._dependentsById.hasOwnProperty(id)){
self._dependentsById[id].invalidate();
}
}
};
Tracker.Dependency.prototype.hasDependents = function () {
var self = this;
for(var id in self._dependentsById)
if (self._dependentsById.hasOwnProperty(id))
return true;
return false;
};
However - It's bad practice to add to Object.prototype, and lots of code will fail in unexpected ways. You'll need to track this down.

Hard to say without more info, but I'd take a look here, specifically the part under "Subscriptions Don't Block":
https://dweldon.silvrback.com/common-mistakes
As the author states, "In meteor, the majority of "Cannot read property of undefined"errors are caused by an incorrect assumption about the existence of subscribed data."
In other words, you may be trying to access the invalidate property before your subscriptions has returned anything.

Related

Uncaught (in promise) RangeError: Maximum call stack size exceeded firebase

I am simply trying to add a record to the database with a cloud function. For some reason, I am getting the above error. This doesn't make sense as I am not making any calls inside the method. At first, I thought it might have something to do with a return, but I tried every combination of return or not returning and nothing worked. Please help
Here is how I call the cloud function
function sendFriendRequest(userUid)
{
//userUid is user that will recieve request
var curUser = firebase.auth().currentUser;
userUid = userUid.substring(1);
var sendRequest = firebase.functions().httpsCallable('sendFriendRequest');
sendRequest({data: {sendingUser: curUser, recievingUser: userUid}}).then(function(result) {
//No return
});
}
Here is the cloud function
exports.sendFriendRequest = functions.https.onCall((data, context) => {
console.log("Made it to sendFriendRequest");
var requestedUserProfileRef = admin.database().ref("Users/" + data.data.recievingUser + "/FriendRequests");
requestedUserProfileRef.child(data.data.sendingUser.uid).set(data.data.sendingUser.displayName);
console.log("Finished sendFriendRequest");
});
I eventually figured this out and thought that I might as well share it with anyone who might need it in the future. So what was wrong was that I was passing in an object as the value for sendingUser. Apparently, you cant do that. Its a weird error and it doesn't seem to correspond to the actual error.

Unexpected TypeError: Cannot read property 'apply' of undefined (meteor-rxjs)

I'm getting an exception and don't understand why. The sample code is cut down from the original, but the line in question starts let subscription=. This code is within a method so only occurs on the server side.
The failing line within Meteor subscribe():
return Meteor.subscribe.apply(Meteor, [name].concat(args.concat([{...
Here's the exception and traceback:
Exception while invoking method 'someMethod' TypeError: Cannot read property 'apply' of undefined
at subscribe (c:\Build\myapp\node_modules\meteor-rxjs\dist\bundles\index.umd.js:609:36)
at Observable._subscribe (c:\Build\myapp\node_modules\meteor-rxjs\dist\bundles\index.umd.js:628:30)
at ZoneOperator.call (c:\Build\myapp\node_modules\meteor-rxjs\dist\bundles\index.umd.js:695:23)
at Observable.subscribe (c:\Build\myapp\node_modules\rxjs\Observable.js:42:22)
Here's my code within a Meteor method:
let list = MyCollection.find(aselector);
let subscription= MeteorObservable.subscribe("publishedList, selector).zone().subscribe( () => {
list = MyCollection.find(selector);
let myArray = list.fetch();
let item: MyItem = myArray.length > 0? myArray[0]: null;
});
The Meteor method should not contain subscribes, since the collection operations are synchronous in the simple case (no callback). Removing the extra code that came from trying to solve the issue and ignoring edge cases, the code can be simplified to:
let item: MyItem = MyCollection.findOne(selector);

Cannot read property of undefined, but property exists

I am getting a curious error in a template helper and I was hoping someone could lay eyes on it with me. Basically the error I'm getting in the console of the client is that the getArena().height is undefined. However, console.log(getArena().height) returns the correct property value. It appears to be a timing issue causing me to get the error, but my application is actually working. What can I do to alleviate this console error?
//My template helper function
yGrids: function() {
console.log(getArena);
console.log(getArena().height);
var yArray = [];
for (var i=0;i<(getArena().height);i++){
yArray.push({});
}
return yArray;
},
// The console results
function getArena() { // 50
return Arenas.findOne(Session.get('arena_id')); …
Exception in template helper: TypeError: Cannot read property 'height' of undefined
at Object.yGrids (http://localhost:3000/app/app.js?hash=c17abf51d6af6541e868fa3fd0b26e34eea2df28:94:35)
at http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:2994:16
at http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:1653:16
at http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:3046:66
at Function.Template._withTemplateInstanceFunc (http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:3687:12)
at http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:3045:27
at Object.Spacebars.call (http://localhost:3000/packages/spacebars.js?hash=65db8b6a8e3fca189b416de702967b1cb83d57d5:172:18)
at http://localhost:3000/app/app.js?hash=c17abf51d6af6541e868fa3fd0b26e34eea2df28:24:22
at .<anonymous> (http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:2754:17)
at http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:1875:20
function getArena() { // 50
return Arenas.findOne(Session.get('arena_id')); …
2
This is a very common issue in Meteor helpers when referring to a collection which may not yet have been loaded via a subscription. In general you want to show a loading template instead of your actual layout until your subscription is ready. Or (less elegant) you can defend yourself with:
var arena = getArena();
var height = arena && arena.height;
Whatever getArena() returns you ought to store it in the reactive variable by setting the reactive variable and you can access the reactive var in helper by get() method

Firebase remove+limited query caching bug?

If I read a value from Firebase and then remove it, a subsequent limited read (e.g. dataRef.limit(10).once("value") ) will still see the removed value.
If I do an unlimited read, then I won't see the removed value, and a subsequent limited read will also no longer see the removed value.
var gFirebase = new Firebase("https://brianshmrian.firebaseio.com/");
function CreateValue()
{
gFirebase.child("TestBug/Key").set("Value");
}
function ReadValue(limit)
{
var dataRef = gFirebase.child("TestBug");
if (limit)
dataRef = dataRef.limit(10);
dataRef.once("value",function(snapshot)
{
alert((limit?"Limited read\n":"Normal read\n") + snapshot.val());
});
}
function RemoveValue()
{
gFirebase.child("TestBug/Key").remove();
}
In this example code, if I do a CreateValue(), then a ReadValue(), then a RemoveValue(), then a ReadValue(true), the object will still be reported to me in the last ReadValue(). However, if I do a ReadValue(false), I'll no longer see the value, and a subsequent ReadValue(true) will not see the value either.
See here to try it for yourself: http://jsfiddle.net/brianshmrian/5WWR6/
So is this a bug? Or am I making a mistake?
EDIT
Ok, that seems like a not too painful workaround. The code below solves my problem for now:
// Need to do this before the remove to avoid caching problem
dataRef.on("value", function(snapshot)
{
setTimeout(function() { dataRef.off(); }, 3000);
});
dataRef.remove();
I can't find any issues with the code. There is always the gotcha that locally cached data is returned synchronously, but I don't see that as an issue here; there's no way for the read to be getting called before the remove has completed. It looks like a pretty straightforward bug.
I was able to circumvent the behavior by setting up the limit(10).on('value') before calling the add/delete operations. So I think that if you establish your query ref first, you'll be okay.
Example: http://jsfiddle.net/katowulf/6wQFF/2/ (the pre tag is set up on load)

backbone.js collection not responding to .each

I have what should be very simple. I create a new collection, and I want to pass it to a render and add the collection models to the page.
get_results: function(){
$.getJson(this.url,function(response){
this.search_results = new Kitchon.Collections.searchList(response);
console.log(this.search_results);
this.search_results.each(this.render_match);
}
},
render_match: function(model){
console.log(model)
},
This returns an error
Uncaught TypeError: undefined is not a function
my collection has an ordinary structure
_byCid: Object
_byId: Object
_onModelEvent: function () { [native code] }
_removeReference: function () { [native code] }
length: 7
models: Array[7]
__proto__: o
I've tried LOTS of things, but one thing that stuck out was maybe I had to pass
this.search_results.models.each(this.render_match); as that is the actual array, but if I do that I get a Uncaught typeError: Object [object Object],[object Object],...
you lose the execution context when callback function for each method is called
use _.bind(this.render_match, this) when passing callback to make sure that render_match has the right context
and you were getting error because you didn't wrap the callback function for getJson method neither. You have to use underscore bind method there as well.
You should read a bit about javascript this and how to tame it - try here http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/
Correct code should look more or less like this...
get_results: function(){
$.getJSON(this.url, _.bind(function(response){
this.search_results = new Kitchon.Collections.searchList(response);
console.log(this.search_results);
this.search_results.each(_.bind(this.render_match, this));
}, this));
},
render_match: function(model){
console.log(model)
},
Though from what I seee - I assume the code you've shown here is either a model or collection - is handling rendering the view - you shouldn't do that! Models and Collections are only to store and parse data - all rendering and controlling application flow should be done in the View(Controllers) with help of the Router.
$.getJson changes the this reference. Many methods in jquery do that, so the value of this.render_match is null. You pass null to each and it fails.
To solve that, create a reference to this (like var _this = this;) before $.getJson and use it instead of this. Code should be like below:
get_results: function(){
var _this = this;
$.getJson(this.url,function(response){
_this.search_results = new Kitchon.Collections.searchList(response);
console.log(_this.search_results);
_this.search_results.each(_this.render_match);
}
},
render_match: function(model){
console.log(model)
},
Just taking a stab here (I don't know anything about Backbone.js), but isn't this what you are looking for:
$.each(this.search_results, function(index, value) {
alert(index + ': ' + value);
});
Good Luck!

Resources