Parse with Meteor JS - javascript

I am using Parse (http://parse.com) inside a Meteor Application (http://meteor.com)
I am trying to query my Parse Database from the server side, and everything is fine until I get to the query.
I get the following error:
[TypeError: Cannot call method 'getItem' of undefined]
This is what my code looks like: [I have even tried query.find()]
var VITxUser = Parse.Object.extend("VITxMaster");
var query = new Parse.Query(VITxUser);
query.equalTo("fbid", "1231212");
//no errors till here
query.first({
success: function(object) {
if (!object){
//insert the user
var GameScore = Parse.Object.extend("VITxMaster");
var gameScore = new GameScore();
gameScore.set("fbid", profile.id);
gameScore.set("registrationNumber", "12DEV0000");
gameScore.set("VITevents", "true");
gameScore.save(null, {
success: function(gameScore) {
// Execute any logic that should take place after the object is saved.
alert('New object created with objectId: ' + gameScore.id + 'and fbid: ' + profile.id);
},
error: function(gameScore, error) {
// Execute any logic that should take place if the save fails.
// error is a Parse.Error with an error code and description.
alert('Failed to create new object, with error code: ' + error.description);
}
});
}
else{
console.log("found object");
console.log(object.get("registrationNumber"));
}
}
});

I can't see a reference to getItem in your code. I suspect however that the issue is due to meteor's variable scoping. Basically in Meteor each file is variable scoped. So you if you had two files file1.js and file2.js they would be wrapped around in a function(){..}.
You would need to remove the variable scoping by not using var to define your variables. Particularly the one's you want to be accessible globally (in other files)

Related

Another Javascript callback issue/example

I've read a good bit about callbacks, and while I use them for click events and similar, I'm using them without fully understanding them.
I have a simple web app with 3 or 4 html pages, each with its own js page.
I have some global functions that I've placed in a new js page which is referenced by each html page that needs it. I'm using this file, word_background.js, to hold functions that are lengthy and used by multiple pages.
pullLibrary is a function, residing in word_background.js, that pulls from my db and processes the results.
I want to call pullLibrary from webpageOne.html, make sure it completes, then do more processing in webpageOne.js.
In webpageOne.js I have the following - trying to call pullLibrary and, once it is complete, use the results for further work in webpageOne.js.
The code executes pullLibrary (in word_background.js) but doesn't "return" to webpageOne.js to continue processing.
I'm assuming I'm missing some critical, essential aspect to callbacks...
I just want to run the pullLibrary function (which has ajax calls etc) and, once it is complete, continue with my page setup.
Any explanation/correction appreciated.
This code is in webpageOne.js:
pullLibrary(function(){
console.log('Now processing library...');
processLibrary();
updateArrays();
//Do a bunch more stuff
});
----- UPDATE -----
Thank you for the comments...which I think are illuminating my broken mental model for how this should work.
pullLibrary is an ajax function - it pulls from a database and stuffs the results into an array and localStorage.
My expectation is that I can call pullLibrary and, when it is complete, the callback code (in this case anonymous function) will run.
function pullLibrary(){ //Values passed from startup() if no data is local
//Pull data from database and create basic LIBRARY array for further processing in processLibrary sub
console.log("Starting to pull library array in background.js..." + "User: " + localStorage.userID + " License: " + localStorage.licType);
var url1 = baseURL + 'accessComments3.php';
var url2 = '&UserID=' + localStorage.userID + '&LicType=' + localStorage.licType;
//Need global index to produce unique IDs
var idIndex = 0;
var index = 0;
$.ajax({
type: "POST",
url: url1,
data: url2,
// dataType: 'text',
dataType: 'json',
success: function(result){
// success: function(responseJSON){
arrLibrary = result; //store for use on this page
localStorage.library = JSON.stringify(result); //Store for use elsewhere
console.log('Saving to global variable: ') + console.log(arrLibrary);
//Now mark last update to both sync storage and local storage so access from other browsers will know to pull data from server or just use local arrays (to save resources)
var timeStamp = Date.now();
var temp = {};
temp['lastSave'] = timeStamp;
// chrome.storage.sync.set(temp, function() {
console.log('Settings saved');
localStorage.lastSync = timeStamp;
console.log('Last update: ' + localStorage.lastSync);
//Store Group List
var arrComGroups = $.map(arrLibrary, function(g){return g.commentGroup});
// console.log('List of comment groups array: ') + console.log(arrComGroups);
arrComGroups = jQuery.unique( arrComGroups ); //remove dupes
// console.log('Unique comment groups array: ') + console.log(arrComGroups);
localStorage.groupList = JSON.stringify(arrComGroups); //Store list of Comment Groups
//Create individual arrays for each Comment Groups
$.each(arrComGroups,function(i,gName){ //Cycle through each group of Comments
var arrTempGroup = []; //to hold an array for one comment group
arrTempGroup = $.grep(arrLibrary, function (row, i){
return row.commentGroup == gName;
});
//Store string version of each Comment Array
window.localStorage['group_' + gName] = JSON.stringify(arrTempGroup);
console.log('Creating context menu GROUPS: ' + gName);
});
// processLibrary(arrLibrary); //We've pulled the array with all comments - now hand off to processor
}, //End Success
error: function(xhr, status, error) {
alert("Unable to load your library from 11trees' server. Check your internet connection?");
// var err = eval("(" + xhr.responseText + ")");
// console.log('Error message: ' + err.Message);
}
}); //End ajax
}
Okay, there are tons of "here's how callbacks work" posts all over the internet...but I could never get a crystal clear example for the simplest of cases.
Is the following accurate?
We have two javascript files, one.js and two.js.
In one.js we have a function - lets call it apple() - that includes an Ajax call.
two.js does a lot of processing and listening to a particular html page. It needs data from the apple() ajax call. Other pages are going to use apple(), also, so we don't want to just put it in two.js.
Here's how I now understand callbacks:
one.js:
function apple(callback_function_name){
$.ajax({
type: "POST",
url: url1,
data: url2,
dataType: 'json',
success: function(result){
//apple processing of result
callback_function_name(); //This is the important part - whatever function was passed from two.js
}, //End Success
error: function(xhr, status, error) {
}
}); //End ajax
} //End apple function
** two.js **
This js file has all kinds of listeners etc.
$(document).ready(function () {
apple(function(apple_callback){
//all kinds of stuff that depends on the ajax call completing
//note that we've passed "apple_callback" as the function callback name...which is stored in the apple function as "callback_function_name".
//When the ajax call is successful, the callback - in this case, the function in two.js, will be called back...and the additional code will run
//So the function apple can be called by all sorts of other functions...as long as they include a function name that is passed. Like apple(anothercallback){} and apple(thirdcallback){}
}); //End apple function
}); //End Document.Ready

Parse cloud code - query user issue in "normal" function

I cannot get cloud code to query a user when using a "standard" function...
If I define the function (as below), it works fine...
Parse.Cloud.define("findUser1", function(request, response){
Parse.Cloud.useMasterKey();
var query = new Parse.Query(Parse.User);
query.equalTo("objectId", "2FSYI1hoJ8"); // "2FSYI1hoJ8" is the objectId of the User I am looking for
query.first({
success: function(user){
response.success(user);
},
error: function(error) {
console.error(error);
response.error("An error occured while lookup the users objectid");
}
});
});
In this version, the function will be called, but the query within will not...
function findThisUser(theObject){
console.log("findThisUser has fired... " + theObject); //confirms "theObject" has been passed in
Parse.Cloud.useMasterKey();
var query = new Parse.Query(Parse.User);
query.equalTo("objectId", "2FSYI1hoJ8"); // "2FSYI1hoJ8" is the value of "theObject", just hard coded for testing
query.first({
success: function(users){
console.log("the user is... " + users);
// do needed functionality here
},
error: function(error) {
console.error(error);
}
});
};
Cloud code does not allow global variables, and I do not see how to pass in a variable to a "defined" function from another one. This is crucial as an outside function must be called to run the required tasks on the returned user. (This happens elsewhere and has to happen AFTER everything else does. This is the confirmation, and is supposed to be used by other functions as well) All potential information found to date has not helped, and the only experience I have in server side javascript is what I have cobbled together from other cloud code...
Any ideas on what I am missing?
This link may help, i had similar issue yesterday and after moving the code a little, and having the response.success(user); in my function all worked fine.
Parse Cloud Code retrieving a user with objectId
Not your exact issue - but this may help.
Heres is the code i use now:
Parse.Cloud.define("getUserById", function (request, response) {
//Example where an objectId is passed to a cloud function.
var id = request.params.objectId;
Parse.Cloud.useMasterKey();
var query = new Parse.Query(Parse.User);
query.equalTo("ObjectId", id);
query.first(
{
success: function(res) {
response.success(res);
},
error: function(err) {
response.error(err);
}
});
});

Cannot create a pointer to an unsaved ParseObject

I am having troubles referring to a "User" object from inside a query. I have the following code:
Parse.Cloud.define("getTabsBadges", function(request, response) {
var UserObject = Parse.Object.extend('User');
var user = new UserObject();
user.id = request.params.userId;
// Count all the locked messages sent to the user
var receivedMessagesQuery = new Parse.Query('Message');
receivedMessagesQuery.equalTo('status', 'L');
receivedMessagesQuery.equalTo('toUser', user); // THIS LINE GENERATES THE ERROR
receivedMessagesQuery.count({
// more code here
});
});
I call the function using CURL but I always get the following error:
{"code":141,"error":"Error: Cannot create a pointer to an unsaved
ParseObject\n at n.value (Parse.js:14:4389)\n at n
(Parse.js:16:1219)\n at r.default (Parse.js:16:2422)\n at e.a.value
(Parse.js:15:1931)\n at main.js:9:25"}
I am using the exactly same code in another project, the only difference is that instead of counting objects I find them and its works correctly. I have also verified that the tables have a column type of Pointer<_User> in both projects. What's causing the problem?
The error message Cannot create a pointer to an unsaved means that you are trying to use an object which does not exist in the Parse DB.
With var user = new UserObject();, you're creating a new user object. You cannot use it in a query until you save it to Parse.
Instead of creating a new User object and setting it's objectId, do a query for the User object. See code below:
Parse.Cloud.define("getTabsBadges", function(request, response) {
var UserObject = Parse.Object.extend('User');
var query = new Parse.Query(UserObject);
query.get(request.params.userId, {
success: function(user) {
// Count all the locked messages sent to the user
var receivedMessagesQuery = new Parse.Query('Message');
receivedMessagesQuery.equalTo('status', 'L');
receivedMessagesQuery.equalTo('toUser', user); // THIS LINE GENERATES THE ERROR
receivedMessagesQuery.count({
// more code here
});
},
error: function(error) {
// error fetching your user object
}
});
});
Your request.params.userId may be undefined or null, which causes this error.
Your query constraints cannot compare the Parse Object that is created without data (createWithoutData()) using undefined or null as its objectId.

JavaScript missing parametar

I am coding a block type plugin for Moodle and have this JS code that gives me problems. Since I'm not very familiar with JS and JSON I can't deduce what is the problem.
My code uses this function to add custom action to action link which issues ajax call to php file ...
This is the code:
function block_helpdesk_sendemail(e) {
e.preventDefault();
Y.log('Enetered method');
var sess = {'sesskey=':M.cfg.sesskey};
Y.log(sess);
var ioconfig = {
method: 'GET',
data: {'sesskey=':M.cfg.sesskey},
on: {
success: function (o, response) {
//OK
var data;
try {
data = Y.JSON.parse(response.responseText);
Y.log("RAW JSON DATA: " + data);
} catch (e) {
alert("JSON Parse failed!");
Y.log("JSON Parse failed!");
return;
}
if (data.result) {
alert('Result is OK!');
Y.log('Success');
}
},
failure: function (o, response) {
alert('Not OK!');
Y.log('Failure');
}
}
};
Y.io(M.cfg.wwwroot + '/blocks/helpdesk/sendmail.php', ioconfig);
}
The code pauses in debugger at return line:
Y.namespace('JSON').parse = function (obj, reviver, space) {
return _JSON.parse((typeof obj === 'string' ? obj : obj + ''), reviver, space);
};
I've put M.cfg.sesskey and data variables on watch. I can see sesskey data shown, but data variable shows like this:
data: Object
debuginfo: "Error code: missingparam"
error: "A required parameter (sesskey) was missing"
reproductionlink: "http://localhost:8888/moodle/"
stacktrace: "* line 463 of /lib/setuplib.php: moodle_exception thrown
* line 545 of /lib/moodlelib.php: call to print_error()
* line 70 of /lib/sessionlib.php: call to required_param()
* line 7 of /blocks/helpdesk/sendmail.php: call to confirm_sesskey()"
And this is what my logs show:
Enetered method
Object {sesskey=: "J5iSJS7G99"}
RAW JSON DATA: [object Object]
As #Collett89 said, the JSON definition is wrong. His tip might work, but if you need strict JSON data then code the key as string (with quotes):
var sess = {'sesskey': M.cfg.sesskey};
or
var sess = {"sesskey": M.cfg.sesskey};
See definition in Wikipedia
your declaring sesskey in a bizarre way.
try replacing data: {'sesskey=':M.cfg.sesskey},
with data: {sesskey: M.cfg.sesskey},
it might be worth you reading through this
mdn link for javascript objects.
You usually need to JSON.stringify() the objects sent via ajax.
which may be part of the problem.

Meteor - How to check if an image exists (server-side)

My goal: Show a default image if one does not exist.
My approach: I've created a helper that makes a server-side Meteor.call to check if the image url exists. The helper's intent is to either return a default image path (does not exist) or the dynamic path (image exists).
Where I'm stuck
Helper: On the client, I can successfully console.log the output
from the server-side method (result.statusCode). However, the helper does not return my
desired string in the template (/images/db/...etc).
Method: I'm getting a 200 results
status for ALL file paths, even ones that don't exist. I suspect
this has to do with iron-router's global NotFound template, but not
sure how to get around it. I tried using fs.exists but could never
get it to find a file (all responses were false).
Any and all suggestions most appreciated. If there's a simpler way to accomplish this, I'm all ears.
HTML:
<img src="{{imagePath key}}avatar.jpg">
My helper:
UI.registerHelper('imagePath', function(key){
//Build the Meteor.call url
var $host = document.location.host;
var $imgBaseUrl = '/images/db/'
var $assetPath = $imgBaseUrl + key + '/';
var url = 'http://' + $host + $assetPath + 'bg.jpg';
//Define the default image location
var $assetPathDefault = $imgBaseUrl + 'default' + '/';
//Call the server-side method
Meteor.call('checkIfImageExists', url, function(error, result) {
if (false) {
console.log('Error');
return $assetPathDefault;
} else {
console.log('Result: ' + result.statusCode);
console.log($assetPath);
return $assetPath;
};
});
});
Server-side method
Future = Npm.require('fibers/future');
Meteor.methods({
checkIfImageExists: function(url) {
check(url, String);
var fut = new Future();
this.unblock();
HTTP.get(url, function (error, result) {
if (!error) {
console.log('Found a file!: ' + url);
console.log('Result: ' + result.statusCode);
fut.return (result);
} else {
console.log(error);
console.log('Error: ' + error);
fut.return (false);
};
});
return fut.wait();
}
});
FWIW - I'm adding the "url check" to an old helper that simply inserted a string w/out checking if the image existed. Worked great.
UI.registerHelper('imagePath', function(key){
var baseUrl = '/images/db/';
return baseUrl + key + '/';
});
Your client–side helper doesn't return anything! Check out the structure you've used:
function a() {
...
Meteor.call(..., function b() {
return something;
});
}
The return something is a return statement of function b, while function a has no return statement – thus it returns undefined.
Meteor server-side methods are (and have to be) asynchrounous, while the nature of client-side Javascript implies that the helper methods are synchronous (there is no "wait" in the browser). Thus, to use a server-side method inside a client-side helper you have to take advantage of reactivity. Fortunately, it's pretty easy with a ReactiveDict:
var imagePathDict = new ReactiveDict();
UI.registerHelper('imagePath', function(key) {
...
if(!imagePathDict.get(key)) {
// the path was not initialized, fetch it from the server
Meteor.call(..., function(error, result) {
...
imagePathDict.set(key, result.assetPath);
});
}
// return the reactive path
return imagePathDict.get(key);
});
By the way, don't start your variable names with $ (unless you refer to a jQuery object), it's against conventions in Javascript.

Categories

Resources