In the below cloud code i would like to get a feedback of the saveAll function but after calling the code from my client in the parse Logs page i can only see:
I2014-10-08T15:28:32.930Z] v249: Ran cloud function acceptMeetingBis for user dyGu143Xho with:
Input: {"meetingId":"bUSTGNhOer"}
Result: Meeting accepted
Here is my cloud code:
Parse.Cloud.define("acceptMeetingBis", function(request, response) {
var userAcceptingTheMeeting = request.user;
var meetingId = request.params.meetingId;
var changedObjects = [];
var queryForMeeting = new Parse.Query("MeetingObject");
queryForMeeting.equalTo("objectId", meetingId);
queryForMeeting.first({
success: function(meeting) {
var userCreatorOfMeeting = meeting.get("user");
userAcceptingTheMeeting.increment("acceptedMeetings", +1);
changedObjects.push(userAcceptingTheMeeting);
meeting.add("participantsObjectId", userAcceptingTheMeeting.id);
if (meeting.get("participantsObjectId").length === meeting.get("meetingNumberOfPersons")) {
meeting.set("isAvailable", false);
}
changedObjects.push(meeting);
Parse.Object.saveAll(changedObjects, {
success: function(objects) {
console.log("Successfully saved objects"); //this line doesn't show up
response.success("objects saved");
},
error: function(error) {
// An error occurred while saving one of the objects.
response.error(error);
}
});
//future query and push notifications will go here
response.success("Meeting accepted");
},
error: function() {
response.error("Failed to accept the meeting");
}
});
});
I will also need to add some push and another nested query after the saveAll() but before doing/trying that i would like to know if this is the right method to use or if i have to build the code in a different way. I'm new to javascript and honestly i'm struggling to understand some concepts, like promises. Any help would be much appreciated.
Your call to
Parse.Object.saveAll
is asynchronous, and you call
response.success("Meeting accepted")
immediately after making the asynchronous call, which ends the cloud code running of the method. If you simply replace the
response.success("objects saved")
with
response.success("Meeting accepted")
you should get what you want.
I didn't see the rest of your question about promises. You should check out Parse's documentation on chaining promises, which is what you want here.
Essentially, here's what you'll want to do:
Parse.Cloud.define("acceptMeetingBis", function(request, response) {
var userAcceptingTheMeeting = request.user;
var meetingId = request.params.meetingId;
var changedObjects = [];
var meetingToAccept;
var queryForMeeting = new Parse.Query("MeetingObject");
queryForMeeting.get(meetingId).then(function(meeting) {
meetingToAccept = meeting;
var userCreatorOfMeeting = meeting.get("user");
userAcceptingTheMeeting.increment("acceptedMeetings", +1);
return userAcceptingTheMeeting.save();
}).then(function(userWhoAcceptedMeetingNowSaved) {
meetingToAccept.add("participantsObjectId", userWhoAcceptedMeetingNowSaved.id);
if (meetingToAccept.get("participantsObjectId").length === meetingToAccept.get("meetingNumberOfPersons")) {
meetingToAccept.set("isAvailable", false);
}
return meetingToAccept.save();
}).then(function(savedMeeting) {
response.success("Meeting accepted");
}, function(error) {
response.error("Failed to accept the meeting");
});
});
For each asynchronous action you want to do, perform it at the end of one of the .then functions and return the result (it returns a promise). Keep adding .then functions until you're done all the work you want to do, at which point call response.success.
Related
I have an API Gateway method calling a Lambda Node.js function. The Lambda function calls SNS and posts an APNS notification to my iPhone. When I invoke the API gateway or the Lambda function in the AWS console, I get one notification as expected. I also get one notification when running the Lambda code on the command line (Grunt and Node.js). I also get one notification when running the javascript from eclipse.
However, when I POST to the API gateway, I get 2-5 notifications. Every thing looks the same. I checked the Cloudwatch logs and it seems only one request is sent each time. Anybody have any idea how to debug this?
I've had similar. For me, it was that I wasn't calling the success callback properly.
I figured it out. I had my function outside the exports.handler function:
var AWS = require('aws-sdk');
var sns = new AWS.SNS();
var myAlerter = function(){
var numSent = 0;
var callback;
var arn = "arn:aws:sns:us-west-2:45435475457:endpoint/APNS/MyAlerter/5a11c61f-1122-3344-5566-656845463";
var sendNotification = function(messageText){
var apns = {
aps : {
alert : messageText,
sound : 'default'
}
};
var message = {
"APNS" : JSON.stringify(apns)
};
message = JSON.stringify(message);
var params = {
Message: message,
MessageStructure: 'json',
TargetArn: arn
};
numSent++;
sns.publish(params, function(err, data){
if (err){
callback(err, err.stack);
}else {
var result = {
error: false,
numSent : numSent,
data: data
};
callback(false,result);
}
});
};
return {
alert : function(message, cb){
callback = cb;
sendNotification(message);
}
}
}();
exports.handler = function(event, context){
var alertedCallback = function(error, data){
if (error){
context.done(error);
} else {
context.succeed(data);
}
};
myAlerter.alert(event.message, alertedCallback);
};
Everytime I called the API Gateway and invoked my Lambda function, the numSent variable would increment. I guess putting my function inside the exports.handler ensured that my function wasn't global or something.
I would like to cache my records once they are received, but I can't figure out how. According to the Documentation you can just call this.store.push('model', record), but it doesn't seem to work. Ember requests the data from the server with each call of the route, I would like to do this only once and use the local store after it is fetched from the server.
If I try to debug it as suggested by the Documentation, i get that there is no cache:
Pd.__container__.lookup('store:main').recordCache
// --> undefined
This is my route (where I try to cache it):
Pd.ProductsRoute = Ember.Route.extend({
model: function () {
var promise = this.store.find('product');
var that = this;
promise.then(function(value) {
// Caching supposed to happen here
value.content.forEach(function(product){
that.store.push('product', product);
});
}, function(reason) {
// on rejection
});
return promise;
}
});
And this the according Adapter (seems to work fine):
Pd.ProductAdapter = DS.RESTAdapter.extend({
primaryKey: 'nid', // DOES NOT WORK BUT I CAN LIVE WITH THAT (SEE WORKAROUND)
findAll: function(store, type) {
var url = 'ws/rest/products';
return new Ember.RSVP.Promise(function(resolve, reject) {
jQuery.getJSON(url).then(function(data) {
Ember.Logger.debug("Received Products:"); // TRIGGERS EVERY TIME!
var srcPattern = /src=["']([^'"]+)/;
data.forEach(function(product){
product.id = product.nid;
product.field_image = srcPattern.exec(product.field_image)[1];
});
Ember.Logger.debug(data);
Ember.run(null, resolve, {product: data});
}, function(jqXHR) {
jqXHR.then = null; // tame jQuery's ill mannered promises
Ember.run(null, reject, jqXHR);
});
});
}
});
this.store.find('type') will always make a call to the server for records. If you only want to make a call to the server once do it in the ApplicationRoute and then instead of using find use the all filter inside of the route that's hit multiple times.
Pd.ApplicationRoute = Em.Route.extend({
model: function(params){
return Em.RSVP.hash({
product: this.store.find('product'),
somethingElse: otherPromise
})
}
});
Pd.ProductRoute = Em.Route.extend({
model: function(params){
return this.store.all('product');
}
});
If you just want to prep the store with your products, you don't even need to return it, or use it in the app route
Pd.ApplicationRoute = Em.Route.extend({
model: function(params){
this.store.find('product');
return {foo:'bar'}; // or return nothing, it doesn't matter
}
});
Lazy loading the models
App.ProductRoute = Ember.Route.extend({
hasPreLoaded: false,
model: function() {
if(this.get('hasPreLoaded')){
return this.store.all('product');
} else {
this.toggleProperty('hasPreLoaded');
return this.store.find('product');
}
}
});
Example
http://emberjs.jsbin.com/OxIDiVU/482/edit
You don't define the primary key on the adapter, it goes on the serializer
Pd.ProductSerializer = DS.RESTSerializer.extend({
primaryKey: 'nid'
});
The cache no longer lives there, it lives in this.store.typeMapFor(Pd.Product) or this.store.typeMaps.
The site is still referencing an older version of ember data until ember data 1.0 is released, I'll assume you're using 1.0 beta version. This document is more up to date https://github.com/emberjs/data/blob/master/TRANSITION.md
My Parse cloud code is structured like so:
Parse.Cloud.define("eBayCategorySearch", function(request, response) {
url = 'http://svcs.ebay.com/services/search/FindingService/v1?SECURITY-APPNAME=*APP ID GOES HERE*';
Parse.Cloud.httpRequest({
url: url,
params: {
'OPERATION-NAME' : findItemsByKeywords,
'SERVICE-VERSION' : '1.12.0',
'RESPONSE-DATA-FORMAT' : JSON,
'callback' : _cb_findItemsByKeywords,
'itemFilter(3).name=ListingType' : 'itemFilter(3).value=FixedPrice',
'keywords' : request.params.item,
// your other params
},
success: function (httpResponse) {
// deal with success and respond to query
},
error: function (httpResponse) {
console.log('error!!!');
console.error('Request failed with response code ' + httpResponse.status);
}
});
});
and I call the function from within my iOS app like so:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (sender != self.nextButton) return;
if (self.itemSearch.text.length > 0) {
[PFCloud callFunctionInBackground:#"eBayCategorySearch"
withParameters:#{#"item": self.itemSearch.text}
block:^(NSNumber *category, NSError *error) {
if (!error) {NSLog(#"Successfully pinged eBay!");
}
}];
}
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
Essentially what I want to do is take whatever search query a user types into the itemSearch field, ping eBay's database, and return the categoryID with the most results. However, rather than logging "Successfully pinged eBay!", Parse is giving the following error: Error: function not found (Code: 141, Version: 1.2.18)
I'm guessing there is something wrong with the function itself. I have seen several examples of that error message when indeed it was the function malfunctioning, not missing.
In the cloud code guide, I found this example:
Parse.Cloud.define("averageStars", function(request, response) {
var query = new Parse.Query("Review");
query.equalTo("movie", request.params.movie);
query.find({
success: function(results) {
var sum = 0;
for (var i = 0; i < results.length; ++i) {
sum += results[i].get("stars");
}
response.success(sum / results.length);
},
error: function() {
response.error("movie lookup failed");
}
});
});
This function calls response.success and response.error, depending on state. It seems yours do not.
Check your success Function. It is not calling `response.success(); .
Also go to the dashboard and check if your function is really updated at main.js because the error message says that "function is not defined".
Just been caught out myself. Problem in my case was very simple
Made a mistake using parse new, and ended up creating a new project called "3" rather than working on the 3rd project in the list. So my Cloud Code function didn't get uploaded to the app I was working on
I want to send data to a specific client. to do that I am trying with the following;
public Task GetWaitingOrdersCount(string id, string clientId)
{
DateTime today = Util.getCurrentDateTime();
var data = 10
return Clients.Client(Context.ConnectionId).loadOrders(data);
//return data;
}
In the above code, I want to send 'data' to the 'clientId' passed to this method.
BUT I m having an error in this line
return Clients.Client(Context.ConnectionId).loadOrders(data);
And the error is
'System.Threading.Tasks.Task<object>' does not contain a definition for 'loadOrders'
the client side code
con.loadOrders = function (data) {
loadOrders(data);
};
function loadOrders(data) {
$('#totalOrders').html(data);
}
Any help about the error???
EDIT:
This is my full client code..
<script type="text/javascript">
var con;
$(document).ready(function () {
con = $.connection.messagingHub;
$.connection.hub.start(function () {
var myClientId = $.connection.hub.id;
con.getWaitingOrdersCount('<%:ViewBag.rid%>',myClientId).done(function (data) {
console.log(data);
});
});
con.client.loadOrders = function (data) {
loadOrders(data);
};
});
function loadOrders(data) {
$('#totalOrders').html(data);
I just tried out your code (slightly modified) and it works fine for me. What version of SignalR are you using? Judging by your server code I'd say 1.0Alpha1+ but your client code looks more like 0.5.3, that is unless your con object is assigned to $.connection.yourhub.client;
If you update to SignalR 1.0Alpha2 and change your client code to be:
var con = $.connection.myCon;// This is arbitrary and would change based on your naming
con.client.loadOrders = function (data) {
loadOrders(data);
};
function loadOrders(data) {
$('#totalOrders').html(data);
}
That being said I believe your issue has to do with the version of SignalR you are using, server side that is: since you're receiving a task oriented error. Another piece of information that might be beneficial would be to know how GetWaitingOrdersCount is being called. Aka is it being invoked from the client directly via: con.server.getWaitingOrdersCount or is it being called from within the hub.
Hope this info helps!
var display_message="";
$('input:checked').each(function(index) {
var profile_id=$(this).val();
$.ajax({
type: 'post',
url: 'myUrl',
data: data,
success: function(data) {
if(data=="ok")
display_message = display_message + data +", ";
}
});
});
alert(display_message);
alert(display_message);
if($.trim(display_message)!=""){
jAlert("Your birthdate already exits in "+display_message.substring(0, display_message.length - 2)+".", "Bdate");
return false;
}
in this code, i use two alert-box for display display_message variable value.
when i run successfully this code, in 1st alert-box i get blank value and second alert-box i get value which i needed, then it will go in if condition.
if i doesn't use alert box then it will always take null value in display_message variable and never enters into the if condition. so what i need to change to run this code without alert box?
You are making an asynchronous call via AJAX, but your code is executing synchronously. So it is returning before the AJAX call completes. The first alert box just gives the function time to catch up. You need to handle all this code in your success callback.
var display_message="";
$('input:checked').each(function(index) {
var profile_id=$(this).val();
$.ajax({
type: 'post',
url: 'myUrl',
data: data,
success: function(data) {
if(data=="ok")
display_message = display_message + data +", ";
if($.trim(display_message)!=""){
jAlert("Your birthdate already exits in "+display_message.substring(0, display_message.length - 2)+".", "Bdate");
return false;
}
});
});
You want all your ajax queries to finish and return results, right?
Then this is a synchronization problem.
I would suggest this approach (code is simplified for clarity).
var inputs_processed = -1;
var inputs_to_process = -1;
function queryData() {
inputs_to_process = $('input:checked').length;
$('input:checked').each(function() {
$.ajax({success: function(data) {
inputs_processed += 1;
// build up that message
}});
});
}
function displayResult() {
if (inputs_processed == inputs_to_process) {
// display result
} else {
// not all queries finished yet. Wait.
setTimeout(displayResult, 500);
}
}
queryData();
displayResult();
Basically, you know how many requests should be made and you don't display result until that number of requests returns.
Why your data is "data"? I cant see any variable called data is declared here. You should pass in the value you want to use as the parameter into the data options.
Edit: This is why u getting the null value. data is not initialize into anything. Only after the success function, your "data" will have the value since you declare the return value with the same name