Meteor.js Collection empty on Client - javascript

Why is it that myCollection.find().fetch() returns an empty array [] even though the call is made within if(data){...}? Doesn't the if statement ensure that the collection has been retrieved before executing the console.log()?
Template.chart.rendered = function() {
var data = myCollection.find().fetch();
if(data) {
console.log(data);
}
$('#chart').render();
}
This returns [] in the browser Javascript console.

You could use count() instead which returns the number of results. data itself would be an empty array, [] which isn't falsey ( [] == true ).
Also don't use fetch() unless you're going to use the raw data for it because its quite taxing. You can loop through it with .forEach if you need to.
var data = myCollection.find();
if(data.count())
console.log(data);
//If you need it for something/Not sure if this is right but just an example
$('#chart').render(data.fetch())

The problem is that you have to wait for data from the server. When you just use Template.name.rendered function it is immediately invoked. You have to use Template.name.helpers function to wait for data from the server. Everything is described in the documentation.

It seems when you "remove autopublish" you have to also subscribe on the client.
if(Meteor.isClient) {
Meteor.startup(function() {
Myvars = new Mongo.Collection("myvars");
Meteor.subscribe('myvars')
});
}
and enable allow and publish on the server
if(Meteor.isServer) {
Meteor.startup(function () {
Myvars = new Mongo.Collection("myvars");
Myvars.allow({
insert: function () {
return true;
},
update: function () {
return true;
},
remove: function () {
return true;
}
});
if (Myvars.find().count() == 0) {
Myvars.insert({myvalue:'annoyed'});
}
Meteor.publish("myvars", function() {
return Myvars.find();
});
});
}
I'm new to this as well. I was just looking to have a global value that all clients could share. Seems like a useful idea (from a beginner's perspective) and a complete oversight on the Meteor teams behalf, it was nowhere clearly documented in this way. I also still have no idea what allow fetch is, that too is completely unclear in the official documentation.

It does, but in javascript you have the following strange behaviour
if ([]){
console.log('Oops it goes inside the if')
} // and it will output this, nontheless it is counter-intuitive
This happens because JS engine casts Boolean([]) to true. You can how different types are casted to Boolean here.
Check if your array is not empty in the beginning.
a = [];
if (a.length){
//do your thing
}

Related

In Vue router, why would this happen? this$1.pending !== route

In most cases, when I use this.$router.push() everything works fine. However, there is one case where I'm doing that that throws an exception. The page changes just fine - it is just that the message vue-router.esm.js?8c4f:2007 Uncaught (in promise) appears in the console.
I don't see anything different in the way I call this particular route than any other.
The code below is where it fails in the router. this$1.pending1 and route are both objects. I put a breakpoint there and checked the following: JSON.stringify(this$1.pending) === JSON.stringify(route) and that returns true, so they have identical data.
In javascript, objects are not considered equal unless they are the same, but I don't know why, in this case, the object is a clone instead of being identical.
runQueue(queue, iterator, function () {
var postEnterCbs = [];
var isValid = function () { return this$1.current === route; };
// wait until async components are resolved before
// extracting in-component enter guards
var enterGuards = extractEnterGuards(activated, postEnterCbs, isValid);
var queue = enterGuards.concat(this$1.router.resolveHooks);
runQueue(queue, iterator, function () {
if (this$1.pending !== route) { // EXCEPTION ON THIS LINE
return abort()
}
this$1.pending = null;
onComplete(route);
if (this$1.router.app) {
this$1.router.app.$nextTick(function () {
postEnterCbs.forEach(function (cb) {
cb();
});
});
}
});
});
This isn't exactly an answer, but here's a discussion of other people who have run into the same thing: https://github.com/vuejs/vue-router/issues/2932
It doesn't sound like there is a resolution, but since it appears harmless, (except for the message in the console), I'm going to not worry about it at the moment.

chrome.storage.sync.get sync with outer level object, but inner object is not sync?

I am trying to use chrome.storage.sync.get to get back the settings. What I don't understand is that when I call console.log(settings), it returns the correct values. But if I call console.log(settings.speeds), it returns the old values. I think this has something to do with the async nature of chrome.storage.sync.get. Can someone please explain what's going on here? And if there's a solution to this. I tried using callback but it didn't help. I guess one solution is to use just one level but that's not what I want.
Thanks all for the help.
var settings = {
speeds: {
speedInput1: 1.0, // after get, new value should be 11.23
speedInput2: 2.0 // after get, new value should be 4.50
},
shortcuts: {
shortCut1: '1',
shortCut2: '2'
}
};
chrome.storage.sync.get(settings, function(result) {
// Retrieve speed settings
for (var key in settings.speeds) {
if (key in result.speeds) {
settings.speeds[key] = result.speeds[key];
}
};
// Retrieve shortcut settings
for (var key in settings.shortcuts) {
if (key in result.shortcuts) {
settings.shortcuts[key] = result.shortcuts[key]
}
};
});
console.log(settings); // correct updated values
console.log(settings.speeds); // old values
I found a workaround for anyone who's interested. I wrapped the get call with a function and call that function and that solve the issue. As to why this solves the issue...I have no idea. Below is an example.
function getChromeStorage() {
chrome.storage.sync.get(settings, function(storage) {
// get stored values back;
}
getChromeStorage(); // calling it as a function solves the asynchronous issue

How to reference a custom jQuery validator method in an $.ajax() success callback?

My apologies for the one millionth iteration of this type of question. I've already seen a number of other posts talking about this, and I still can't wrap my head around being able to invoke a function after the callback is successful and returns. I must have read this post over half a dozen times:
How do I return the response from an asynchronous call?
The Code
Anyway .., my question I hope anyone could shed some light on. I have a custom jQuery validator method that checks if a username is available.
jQuery.validator.addMethod("usernameAvailability",
function(value, element) {
console.log('starting usernameAvailability');
if(this.optional(element) === true){return true;}
else{
console.log('ending usernameAvailability, about to return get_availability');
return availabilityCheck.get_availability('username');
}
}, "Username already in use." );
The custom jQuery validator method calls get_availability(element) in namespace availabilityCheck.
var availabilityCheck = (function() {
var usernameIsAvailable, emailIsAvailable, Callback, AJAX_Availability_Check, change_Availability;
usernameIsAvailable = null;
emailIsAvailable = null;
AJAX_Availability_Check = function(callback, element){
console.log('starting AJAX_Availability_Check');
if(element==="username"){
selection = {username:$('#id_username').val()};
}
else{
selection = {email:$('#id_email').val()};
}
$.ajax({
url: '/register/',
type: 'get',
data: selection,
dataType:'text',
async: true
}).done(Callback(element));
};
change_Availability = function(element, bool) {
if(element === 'username'){
usernameIsAvailable = bool;
}
else{
emailIsAvailable = bool;
}
};
Callback = function(element) {
return function(result, textStatus){
bool = result === "True" ? true: false;
change_Availability(element, bool);
return usernameIsAvailable;
};
};
return{
get_availability: function(element){
AJAX_Availability_Check(Callback, element);
return element === 'username' ? usernameIsAvailable : emailIsAvailable;
}
}
})();
The Problem and My Question
My problem The input correctly validates whether the username is already in use, but the user needs to trigger validation twice since get_availability returns before the Callback can change usernameIsAvailable to the proper boolean.
My Question How do I restructure my code so my custom jQuery validate method is invoked by the callback? Or how do I ensure that it won't validate until the Callback returns?
The problem is your structure... I don't know where you got that from but throw it away and burn it, then forget you ever saw it.
You can simplify your code to look like this:
var availabilityCheck = function() {
var usernameIsAvailable = null, emailIsAvailable = null,
AJAXAvailabilityCheck, changeAvailability;
AJAXAvailabilityCheck = function(element){
console.log('starting AJAX_Availability_Check');
if(element==="username"){
selection = {username:$('#id_username').val()};
}
else{
selection = {email:$('#id_email').val()};
}
$.ajax({
url: '/register/',
type: 'get',
data: selection,
dataType:'text',
async: true
}).done(changeAvailability(element));
};
changeAvailability = function(element, theBool) {
if(element === 'username'){
usernameIsAvailable = theBool;
}
else{
emailIsAvailable = theBool;
}
};
this.getAvailability = function(element) {
AJAXAvailabilityCheck(element);
return element === 'username' ? usernameIsAvailable : emailIsAvailable;
}
};
So your callback is now actually something useful instead of just another useless layer.
However as I point out below, your result wasn't ever actually defined as far as I could tell so your going to have to figure out what theBool should be.
Some things of note:
Callback = function(element) {
return function(result, textStatus){
bool = result === "True" ? true: false;
change_Availability(element, bool);
return usernameIsAvailable;
};
};
You return an anonymous function for no particular reason, and your result variable isn't defined... at least with the code as you have it, so with what you have it's always resolving to false. Also if your just checking for truthyness then you don't need a tuple you can just do result === "True" which will evaluate to true or false, no need for the extra ? true : false.
Also, don't use words like bool for variable names. Bool is a type of variable and is a reserved word. Javascript lets you use it cause... Javascript will let you do just about anything, but its bad practice.
Finally you mixed like 10 different types of casing. Now casing is a personal preference (I personally prefer underscores to camelCase, which is the javascript convention), but no matter what case you use. USE ONLY ONE CASE!
Now I believe your real issue here is that you don't understand what a self-invoking function is for.
You use this syntax: var availabilityCheck = (function(){})(); which creates a self-invoking function; which means that it's going to fire without being called! Which means all this does is call your ajax and cause an extraneous server hit when your user hasn't even entered any data yet.
I believe that you did it so you could use this syntax availabilityCheck.getAvailability() in your invoking function, but the better way to do that is to do what I did above and make getAvailability a property of availabilityCheck by using the this keyword. Then you can use the same syntax without running your whole function twice.
You should almost NEVER (there are always exceptions of course) put an ajax call in a self invoking function. If the call doesn't depend on user input, then you should of just loaded the data when your page was requested the first time.

Dynamically added object properties not being added in Javascript

Please bare bear with me, I'm very new to Javascript. I am pulling my hair out trying to figure out why this won't work. Keep in mind I come from a Java background. I have a function 'getCsvData' and I'm essentially trying to parse a CSV file and dynamically add object properties to the datasource object and then return it. As you can see, outside the function 'getCsvData', I try to log the results after calling my function, but the result object is empty and there are no object propeties added to it.
I have a very strong feeling it has to due with closure/scope chain resolution that I'm still trying to learn and understand.
The questions are: Why aren't the properties added dynamically to the datasource object? I believe they actually are added in the scope of the anonymous function 'function(data)' passed as the second argument to '$.get', but they are immediately gone once the outer function 'getCsvData' returns. Why, and how can I fix this? Thanks!!
<script src="js/jquery-1.10.2.min.js"></script>
<script src="js/knockout-3.0.0.js"></script>
<script src="js/globalize.min.js"></script>
<script src="js/dx.chartjs.js"></script>
<script src="js/jquery.parse.js"></script>
$(function () {
function getCsvData(fileName, groupBy, year) {
var datasource = { }
$.get(fileName, function(data) {
var alldata = $.parse(data, { header: true });
for (var i = 0; i<alldata.results.rows.length;i++) {
var key = alldata.results.rows[i][groupBy]
if (key in datasource) {
datasource[key] = datasource[key] + 1
} else {
datasource[key] = 0
}
}
});
return datasource;
};
var results = getCsvData("data/data.csv", "Priority", 2012);
console.log(results)
for (key in results) {
console.log(key)
}
});
This is because get is called async, so datasource is the return value after initiating the get rather than after receiving the result (i.e. it is empty because the get completion has not been called yet). You should rather indicate completion with a callback or use jQuery.ajax() with the sync option to wait for the response to the get before returning from getCsvData. See here.

Variable scope in Javascript Object

I'm discovering the concept of "objects" in JavaScript. I'm making an RSS Parser, and I have an error (commented).
function MyParser (feed_url) { // Construct
"use strict";
this.feedUrl = feed_url;
this.pubArray = [];
if (typeof (this.init_ok) == 'undefined') {
MyParser.prototype.parse = function () {
"use strict";
var thisObj = this;
$.get(this.feedUrl, function (data, textStatus, jqXHR) {
if (textStatus == 'success') {
var xml = jqXHR.responseXML,
//lastBuildDate = new Date($(xml).find('lastBuildDate').text());
items = $(xml).find('item');
items.each(function () {
var pubSingle = thisObj.makeObj($(this).find('pubDate').text(),
$(this).find('link').text(),
$(this).find('title').text(),
$(this).find('description').text(),
$(this).find('encoded').text(),
$(this).find('commentRss').text(),
$(this).find('comments').last().text());
thisObj.pubArray.push(pubSingle);
});
console.log(thisObj.pubArray); // OK
}
}, 'xml');
console.log(this.pubArray); // Empty
return (this.pubArray);
};
MyParser.prototype.makeObj = function (pubDate, pubLink, pubTitle, pubDesc, pubContent, pubComCount, pubComLink) {
"use strict";
var pubSingle = {};
pubSingle.pubDate = new Date(pubDate);
pubSingle.pubLink = pubLink;
pubSingle.pubTitle = pubTitle;
pubSingle.pubDesc = pubDesc;
pubSingle.pubContent = pubContent;
pubSingle.pubComCount = pubComCount;
pubSingle.pubComLink = pubComLink;
return (pubSingle);
};
}
this.init_ok = true;
}
If you look at the console.log(), you'll see that the line // OK is outputting my array correctly.
But later, when returning from $.get, my array is empty.
Does anybody have an idea why, and how to correct that please?
This is not a problem with variable-scope. The problem here is that you're working with asynchronous flow and you're not thinking correctly the flow.
Let me explain:
When you do your .get, you fire a parallel asynchronous process that will request information from the browser, but your main program's flow keeps going, so when you get to your "return" statement, your array has not been filled yet with the response from your get method.
You should use your array from inside the get callback and not outside of it, since you can't guarantee that the array will have the information you need.
Does it make any sense?
Let me know!
Further explanation
According to your comments, you're still doing something like this:
var results = MyParser(feed_url);
//code that uses results.pubArray
And you cannot do that. Even though you're setting your "pubArray" inside your .get callback, you're trying to use pubArray right after you called MyParser and that's before the .get callback is called.
What you have to do, is call your next step on your program's logic from within the .get callback... that's the only way you can be sure that the pubArray is filled with proper data.
I hope that makes it clearer.
This is because your line
console.log(this.pubArray); // Empty
is being called directly after you issue your Ajax request; it hasn't had time to fetch the data yet. The line
console.log(thisObj.pubArray); // OK
is being called inside the Ajax callback, by which time the data has been fetched.
Thank you all, and particulary #Deleteman .
Here is what I did:
$.get(this.feedUrl, 'xml').success(function () {
thisObj.handleAjax(arguments[0], arguments[1], arguments[2]);
$(document).trigger('MyParserDone');
}).error(function () {
$(document).trigger('MyParserFailed');
});
Then, when i enter "HandleAjax", i'm back in my object context, so "this" refers to my object and the right properties. The only "problem" is that I have to set a listener (MyParserDone) to make sure the parsing is finished.

Categories

Resources