I am trying to get the value of a queried ID called from another class however when I call the function it gives me a promise chain and not the value I am looking for.
The method in the class 'Helper' is below
function querySF() {
var conn = new jsforce.Connection({
// you can change loginUrl to connect to sandbox or prerelease env.
loginUrl: 'https://www.salesforce.com'
});
return conn.login('someusername', 'password')
.then(function(userInfo) {
// Now you can get the access token and instance URL information.
// Save them to establish connection next time.
console.log(conn.accessToken);
console.log(conn.instanceUrl);
// logged in user property
console.log("User ID: " + userInfo.id);
console.log("Org ID: " + userInfo.organizationId);
// ...
return conn.query("SELECT Id FROM some place Where name = 'some name'")
})
.then(function(result) {
console.log("total : " + result.totalSize);
console.log("fetched : " + result.records.length);
// is returning the id
console.log(result.records[0].Id);
return result.records[0].Id; // can see the id here when debugging
})
.catch(function(err) {
console.error(err);
});
}
I am exporting the module like this at the bottom of the class:
exports.querySF = querySF();
The other class called 'BookingEvent' calls the method like this: var theId = Helper.querySF; and it returns a promise, I have printed the promise to console console.log(Helper.querySF); to see the results:
Promise {
_45: 0,
_81: 1,
_65: 'a0L46111001LyvsEAC', // This is the value I need
_54: null,
then: [Function],
stream: [Function: createRequest] }
It was thought that I should be able to just use
helpers.querySF().then(function(value){
console.log(value);
})
and be able to get the value however I am getting this error:
Failed: helpers.querySF is not a function
I am quite new to promises and no one at my company can seem to solve the issue. I have research many different ways of resolving promises however they do not work and I also do not understand. Could someone help me resolve this promise so the id accessible whenever I call this method, which will be multiple times with different queries I will be sending in.
If the promises are not related each other, you may find better Promise.all() here instead of chaining promises in this way. Then resolve all of them. If actually you get the name of the second query from the first promise, actually you need to chain them.
Then you are missing a catch in order to catch errors for the first promise.
And maybe a refactor using function may help the code to look better.
return conn.login('someusername', 'password')
.then(elaborateUserInfo)
.catch(catchErrors)
.then(elaborateResults)
.catch(catchErrors);
function elaborateUserInfo(userInfo) {
// Now you can get the access token and instance URL information.
// Save them to establish connection next time.
console.log(conn.accessToken);
console.log(conn.instanceUrl);
// logged in user property
console.log("User ID: " + userInfo.id);
console.log("Org ID: " + userInfo.organizationId);
// ...
return conn.query("SELECT Id FROM some place Where name = 'some name'");
}
function elaborateResults(result) {
console.log("total : " + result.totalSize);
console.log("fetched : " + result.records.length);
// is returning the id
console.log(result.records[0].Id);
return result.records[0].Id; // can see the id here when debugging
}
function catchErrors(err) {
console.log(err);
}
It looks better, doesn't it?
Instead, the only reason for this error Failed: helpers.querySF is not a function is that you don't have that method in your object. Are you sure you really exported it in order to be visible outside your module?
Related
I'm trying to integrate the Paypal Smart Button and Firestore. Everything was working fine until I tried to add in a check to see if the user document already existed in Firestore to throw an error so users can't register twice.
The next Paypal action (onApproval) requires the subscription id, which is created by the actions.subscription.create() function.
Just to make sure it wasn't a problem with the way the function fired, I also ommitted it, and just had paypalCreate = 'success'. But when logging the result of paypalCreate, at different levels of the nested functions, these were the results and their order:
On Fail (user exists):
Third Creation (undefined)
First Creation error
Second Creation error
On Success (user doesn't exist):
Third Creation (undefined)
First Creation success
So why is the 'Third Creation' always logged first? I'm guessing because the promise hasn't completed. Do I need to add a wait somewhere? And why is it undefined?
And on success, why isn't the 'Second Creation' returned? How is it any different to the failed result?
I need paypalCreate returned at the end of this createSubscription function, so the next step can use the result of it.
The code simplified:
createSubscription: function(data, actions) {
// Get snapshot
db.collection('users').doc(email).get().then((querySnapshot) => {
let paypalCreate;
// Check if email exists
if (querySnapshot.exists) {
// Register as error if user exists <- This works
paypalCreate = 'error';
console.log('First Creation ' + paypalCreate);
} else {
console.log("user doesn't exists");
// Saving new user to Firestore <- This works
db.collection('users').doc(email).set({
name: name,
email: email,
created: firebase.firestore.Timestamp.now()
}),
// Choose plan to subscribe to in PayPal
paypalCreate = actions.subscription.create({
'plan_id': 'XXXX'
});
console.log('First Creation ' + paypalCreate);
return paypalCreate;
};
console.log('Second Creation ' + paypalCreate);
return paypalCreate;
}),
console.log('Third Creation ' + paypalCreate);
return paypalCreate;
},
I have following autoform hook code. How can I get value outside of method.call.
My problem is that when I run method.call, then 'chi' value is undefined. Whereas, on server there is '1' record.But chi doesn't get 'myResult' value. If I comment out the method.call and return 'Gogo', then 'chi' gets this value correctly. Can some one guide me what I am doing wrong and how it can be rectified.
Code:
before: {
method: function(doc) {
var retVal = false ;
var pai = Q.fcall(function(){
if(!_.isEmpty(doc) && _.pick(doc, 'name') ) {
console.log('Ist level, true condition: ', doc);
return true;
}
else{
console.log('Ist level, false condition: ', doc);
return false;
}
})
.then(function(check){
console.log('Check value: ', check);
if( check ){
Meteor.call('CategoryNameAvailable', doc.name, function (error, result) {
console.log('Returned result from server', result);
if (!result) {
if(Contexts.Category.keyIsInvalid('name')){
Contexts.Category.resetValidation('name');
}
console.log('Returned result from server inside if condition ', result);
Collections.Category.simpleSchema().namedContext("CategoryInsertForm").addInvalidKeys([{
name: "name",
type: "notUnique"
}]);
console.log('Doc value in meteor call function: ', doc);
Session.set('retVal', true);
console.log('retVal value in meteor call function: ', retVal);
}
return 'myResult';
});
// return 'Gogo';
/* Meteor call End */
}
})
.then(function(chi){
console.log('Chi value: ', chi);
})
.done();
console.log('Pai value-2: ', pai);
} /* End of method */
} /* End of 'before' hook */
You could check this out https://github.com/stubailo/meteor-reactive-method
It might solve your problem
Do you think you could add in the file where you're defining your method? I had a similar problem recently attempting to do something similar, and it had to do with the formatting of my Method definition.
For me it was misplacing where I was returning data within my method definition. In another instance of another similar problem, I wasn't subscribing to the Collection on the client side.
If thats not the issue, and your call is returning data correctly, its only not passing it outside of the context of the call, you could try and use Session.set to define a session variable that can then be called whenever you need the data.
Its going to be difficult to tell exactly whats going on though without the context of the Method definition.
Im trying to send a push message to everyone with read access every time a new note is saved.
In pseudocode it should get the ACL. Evaluate each member in the ACL and return an array of all users with read access. Then send a push notification to each member.
I've tried running separate task one by one and it works properly. However when I put everything together in the following code I get strange results. Looking at the log I can see it not executing in order as I expect. I first though the getACL call was an asynchronous call so I tried to implement promises with no luck. Then after help from stackoverflow I find out that getACL is not asynchronous therefore the code should just work, right?
This is what I'm trying:
Parse.Cloud.afterSave("Notes", function(request) {
var idsToSend = [];
var i = 0;
console.log("1 start");
var objACL = request.object.getACL();
var ACLinJSON = objACL.toJSON();
console.log("2 ACL = " + ACLinJSON);
for (var key in ACLinJSON) {
if (ACLinJSON[key].read == "true") {
idsToSend[i] = key.id;
console.log("3 i = " + i + " = " + idsToSend[i]);
i++;
}
}
console.log("4 idsToSend = " + idsToSend);
//lookup installations
var query = new Parse.Query(Parse.Installation);
query.containedIn('user', idsToSend);
Parse.Push.send({
where: query,
data: {
alert: "note updated"
}
}, {
success: function() {
console.log("Success sent push");
},
error: function(error) {
console.error("can’t find user"); //error
}
});
});
And this is the response I see from parse log
I2014-08-04T08:08:06.708Z]4 idsToSend =
I2014-08-04T08:08:06.712Z]2 ACL = [object Object]
I2014-08-04T08:08:06.714Z]1 start
I2014-08-04T08:08:06.764Z]Success sent push
Everything is completely out of order??
How can I execute the above function in the way it's written?
I've found the logs are not in order when I run things too, could be a timing issue or something, ignore the order when they're in the same second, I have done other tests to confirm things really do run in order on my own Cloud Code... had me completely confused for a while there.
The issue you're having is that log #3 is never being hit... try tracing ACLinJSON on it's own to see the actual structure. When you append it to a string it outputs [object Object] as you have seen, so do console.log(ACLinJSON); instead.
Here's the structure I've seen:
{
"*":{"read":true},
"Administrator":{"write":true}
}
Based on that I would expect your loop to work, but it may have a different level of wrapping.
UPDATE:
Turns out the issue was looking for the string "true" instead of a boolean true, thus the fix is to replace the following line:
// replace this: if (ACLinJSON[key].read == "true") {
if (ACLinJSON[key].read == true) {
I'm a little confused about where to place a response.success() when using serial Promises.
Here's the situation: I've got a cloud function that accepts an array of email addresses and the current user. The function does the following:
Finds the current user based upon it's user object id.
Iterates over the array of emails addresses
Find if there is an existing user for each given email address
If there is an existing user, we check to see if the existing user and the current user are friends
If they are not friends, it creates a friendship.
Now when I run this function without a response.success(), it does exactly what I expect it to and the friendships entries are created. But no matter where I place the response in the code, I get the resulting response.success message and none of the serialized promises execute.
Why the resulting success/failure matters: I'm executing this function from an iOS app and I'd like to properly handle the success or failure cases correctly on the iOS side.
Here is the cloud function:
Parse.Cloud.define("friendExistingUsers", function(request, response) {
// Get our parameters
var addresses = request.params.emailAddresses;
var userId = request.params.user;
// Query for our user
var userQuery = new Parse.Query("User");
userQuery.equalTo("objectId", userId)
userQuery.first().then(function(currentUser) {
// if we find the user, walk the addresses
var promise = Parse.Promise.as("success");
_.each(addresses, function(address) {
console.log(address);
// add a then to our promise to handle whether a relationship is
// being created.
promise = promise.then(function() {
// find if there is a user for that address
var emailQuery = new Parse.Query("User");
emailQuery.equalTo("email", address);
emailQuery.first().then(function(addressUser) {
if (typeof addressUser != 'undefined') {
// found one.
console.log(addressUser);
// figure out if our current user and this user are
// friends.
var friendQuery = new Parse.Query("FVFriendship");
friendQuery.equalTo("from", currentUser);
friendQuery.equalTo("to", addressUser);
friendQuery.first().then(function(relationship) {
if (typeof relationship != 'undefined') {
// if they are, we need to pass.
console.log("Found a relationship: " = relationship)
} else {
// They are not. Add the friendship
var Friendship = Parse.Object.extend("FVFriendship");
var friendship = new Friendship();
friendship.set("from", currentUser);
friendship.set("to", addressUser);
friendship.save().then(function(result) {
console.log("Created a friendship: " + result)
});
};
});
} else {
// we did not find a user for that address
console.log("No user for " + address);
};
});
});
});
console.log(promise);
return promise;
}).then(function() {
response.success("success");
});
});
Thanks in Advance. Let me know if there's anything else I can add.
Your .then callback function attached to promise should return a promise. Missing this is a common mistake when using promises.
Also Parse doesn't seem to show objects with console.log as browsers do, so I wrap them into JSON.stringify().
The question title is rather vague, but here's my situation. I have roughly 700+ lines of jQuery for a web application, each function and "major point of interest" in the code noted by a log to the console when it fires. For example, I have a few functions that use an AJAX call to a servlet to retrieve some information. I log when the AJAX request begins, if it's succeeded (then print what data it gathered), etc. So, by the look of what my console has logged when I open the page, it seems to stop after the first AJAX call. Granted, the call seemed to work just fine, and the data it returned was perfect. As you'll see, it even populated the select box as intended. However, the console logs stop shortly after, making me believe that for some reason, the other functions are not being called...
jQuery
$(document).ready(function() {
Initialize();
});
function Initialize() {
console.log("Initializing...");
User();
Widgets();
if($.cookie("fogbugzId") != null) {
console.log("Stored ID: " + $.cookie("fogbugzId"));
$("#userSelect").val($.cookie("fogbugzId")).trigger("change");
$("#userSelect").hide();
} else console.log("No ID Stored!");
}
function User() {
console.log("Initializing User...");
$.each(FetchUsers(), function(index, user) {
$("#userSelect").append($("<option>").val(user.id).text(user.name));
});
$("#userSelect").change(function() {
if($("#userSelect").val() != "") {
console.log("User Changed to " + $("#userSelect").val() + ": " + $("#userSelect").text());
$.cookie("fogbugzId", $("#userSelect").val(), { expires: 365 });
}
Update();
});
console.log("User Initialized!");
}
function FetchUsers() {
console.log("Loading Users...");
$("#loading").show();
$.get(servlet, { command: "getUsers" }, function(data) {
var users = new Array();
$(data).find("user").each(function() {
users.push({
id: $(this).find("id").text(),
name: $(this).find("name").text()
});
});
$.each(users, function(index, user) {
console.log(">> " + user.id + ": " + user.name);
});
console.log("Users Loaded!");
return(users);
}, "xml").complete(function() {
$("#loading").hide();
}).error(function() {
console.log("Loading Users Failed!");
});
}
function Widgets() {
console.log("Initializing Widgets...");
// More Code
console.log("Widgets Initialized!");
}
Console
Initializing...
Initializing User...
Loading Users...
>> 267: Alex Molthan
>> 35: Bill Brinkoetter
>> 100: Bob Yoder
>> 189: Brian Cutler
>> 559: Brian Ormond
>> 400: Corey Nakamura
Users Loaded!
But the logging stops right there. So the AJAX call to fetch the users from the database works fine, but apparently the User() function doesn't manage to finish properly. The only error that the JavaScript console gives me is one within my jquery.min.js file:
Uncaught TypeError: Cannot read property 'length' of undefined jquery.min.js:16
f.e.extend.each jquery.min.js:16
User modifytime.js:14
Initialize modifytime.js:3
(anonymous function) modifyTime.jsp:21
f.extend._Deferred.e.resolveWith jquery.min.js:16
f.e.extend.ready jquery.min.js:16
f.c.addEventListener.B jquery.min.js:16
It looks as though it is breaking on the $.each() that iterates through the array of users returned by the FetchUsers() function. I know the function returns usable array, so I'm not sure what it's getting stuck on. Can anyone see something I'm missing right off the bat? I tried assigning the users[] returned by the FetchUsers() function into a variable first, then passing that into the $.each(), but it still didn't work. Any suggestions?
Edit: After replacing the minified version of jQuery with the uncompressed version, it seems as though the array of users that I pass into the $.each() function has now .length property, which is why it's breaking. Just to check, before I call that particular $.each() function, I placed a log of the users[].length returned from the FetchUsers() function to see that it still had no .length property. I then went to the FetchUsers() function itself and placed a log of the users[].length just before I return it. This log, however, works perfectly fine (though my example doesn't show it, it returns 40 users). So is my users[] not being returned as an array or something?
FetchUsers does not return anything, it does not even have a return statement. Additionally, $.get is an asynchronous function, so you cannot return the value it passes to its callback from the FetchUsers function. Instead, you could make FetchUsers take a callback it calls when it has received data of a user (and in this case doing that change would be relatively trivial):
function User() {
console.log("Initializing User...");
FetchUsers(function(user) { // Changed!
$("#userSelect").append($("<option>").val(user.id).text(user.name));
});
<...>
}
function FetchUsers(callback) { // Changed!
console.log("Loading Users...");
$("#loading").show();
$.get(servlet, { command: "getUsers" }, function(data) {
//var users = new Array(); No longer necessary.
$(data).find("user").each(function() {
callback({ // Changed!
id: $(this).find("id").text(),
name: $(this).find("name").text()
});
});
<...>
}
Changing those three lines with the "Changed!" comment should be enough to make it work correctly. (Though your logging of the users gotten will need to be slightly altered as they are no longer pushed into an array.)
I confess I have not read and understood every part of your source (nor checked if all the braces are closed), but FetchUsers clearly does NOT return anything (contrary to your claim) - so a call to FetchUsers() evaluates to 'undefined'. Fixing it will require some rewriting as in Javascript you cannot really return a result of asynchronous operation (like $.get) from a synchronous function (like FetchUsers()) - this would require multithreading (some kind of blocking, waiting etc).