How to save my model using Parse cloud js? - javascript

I had a read of the meme example but it doesn't seem to update, just create new objects! What I want is to
a. find some given db table
b. update some fields in the db table
c. save the db table back to the database
Given this code, what is the missing piece so that I can actually update an object?
query.find(
function(results){
if (results.length > 0){
return results[0];
} else {
//no object found, so i want to make an object... do i do that here?
return null;
}
},
function(error){
response.error("ServerDown");
console.error("ServerDown - getModuleIfAny URGENT. Failed to retrieve from the ModuleResults table" + +error.code+ " " +error.message);
}
).then(
function(obj){
var module;
if (obj != null){
console.log("old");
module = obj;
module.moduleId = 10; //let's just say this is where i update the field
//is this how i'd update some column in the database?
} else {
console.log("new");
var theModuleClass = Parse.Object.extend("ModuleResults");
module= new theModuleClass();
}
module.save().then(
function(){
response.success("YAY");
},
function(error) {
response.error('Failed saving: '+error.code);
}
);
},
function(error){
console.log("sod");
}
);
I thought the above code would work - but it does not. When it finds an object, it instead refuses to save, stupidly telling me that my object has no "save" method.

First I would double check the version of the javascript sdk you're using in your cloud code. Make sure it's up to date e.g. 1.2.8. The version is set in the config/global.json file under your cloud code directory.
Assuming you're up to date I would try modifying your code by chaining the promises using multiple then's like so:
query.find().then(function(results){
if (results.length > 0){
return results[0];
} else {
//no object found, so i want to make an object... do i do that here?
return null;
}
},
function(error){
response.error("ServerDown");
console.error("ServerDown - getModuleIfAny URGENT. Failed to retrieve from the ModuleResults table" + +error.code+ " " +error.message);
}).then(function(obj){
var module;
if (obj != null){
console.log("old");
module = obj;
module.moduleId = 10; //let's just say this is where i update the field
//is this how i'd update some column in the database?
} else {
console.log("new");
var theModuleClass = Parse.Object.extend("ModuleResults");
module= new theModuleClass();
}
module.save();
}).then(function(result) {
// the object was saved.
},
function(error) {
// there was some error.
});
I think this should work. Fingers crossed. Cheers!

Related

Dynamics CRM 2016 Javascript forEach not supported

So I am trying to write javascript code for a ribbon button in Dynamics CRM 2016 that will grab a phone number from a list of Leads that can be seen in the Active Leads window.
However, when I try to run it, I get an error telling me
As I step into my code (I'm debugging), I see this error
Here is the code I am working with.
function updateSelected(SelectedControlSelectedItemIds, SelectedEntityTypeName) {
// this should iterate through the list
SelectedControlSelectedItemIds.forEach(
function (selected, index) {
//this should get the id and name of the selected lead
getPhoneNumber(selected, SelectedEntityTypeName);
});
}
//I should have the lead ID and Name here, but it is returning null
function getPhoneNumber(id, entityName) {
var query = "telephone1";
Sdk.WebApi.retrieveRecord(id, entityName, query, "",
function (result) {
var telephone1 = result.telephone1;
// I'm trying to capture the number and display it via alert.
alert(telephone1);
},
function (error) {
alert(error);
})
}
Any help is appreciated.
What you have is an javascript error. In js you can only use forEach on an array. SelectedControlSelectedItemIds is an object not an array.
To loop though an object, you can do the following.
for (var key in SelectedControlSelectedItemIds){
if(SelectedControlSelectedItemIds.hasOwnProperty(key)){
getPhoneNumber(SelectedControlSelectedItemIds[key], SelectedEntityTypeName)
}
}
Okay, so I figured it out. I had help, so I refuse to take full credit.
First, I had to download the SDK.WEBAPI.
I then had to add the webAPI to my Javascript Actions in the Ribbon Tool Bench.
Then, I had to create a function to remove the brackets around the
SelectedControlSelectedItemIds
Firstly, I had to use the API WITH the forEach method in order for it to work.
These are the revisions to my code.
function removeBraces(str) {
str = str.replace(/[{}]/g, "");
return str;
}
function updateSelected(SelectedControlSelectedItemIds, SelectedEntityTypeName) {
//alert(SelectedEntityTypeName);
SelectedControlSelectedItemIds.forEach(
function (selected, index) {
getPhoneNumber(removeBraces(selected), SelectedEntityTypeName);
// alert(selected);
});
}
function getPhoneNumber(id, entityName) {
var query = "telephone1";
SDK.WEBAPI.retrieveRecord(id, entityName, query, "",
function (result) {
var telephone1 = result.telephone1;
formatted = telephone1.replace(/[- )(]/g,'');
dialready = "1" + formatted;
withcolon = dialready.replace(/(.{1})/g,"$1:")
number = telephone1;
if (Xrm.Page.context.getUserName() == "Jerry Ryback") {
url = "http://111.222.333.444/cgi-bin/api-send_key";
} else if(Xrm.Page.context.getUserName() == "Frank Jane") {
url = "http://222.333.444.555/cgi-bin/api-send_key";
}
else if( Xrm.Page.context.getUserName() == "Bob Gilfred"){
url = "http://333.444.555.666/cgi-bin/api-send_key";
}
else if( Xrm.Page.context.getUserName() == "Cheryl Bradley"){
url = "http://444.555.666.777/cgi-bin/api-send_key";
}
else if( Xrm.Page.context.getUserName() == "Bill Dunny"){
url = "http://555.666.777.888/cgi-bin/api-send_key";
}
if (url != "") {
var params = "passcode=admin&keys=" + withcolon + "SEND";
var http = new XMLHttpRequest();
http.open("GET", url + "?" + params, true);
http.onreadystatechange = function () {
if (http.readyState == 4 && http.status == 200) {
alert(http.responseText);
}
}
http.send(null);
}
},
function (error) {
// alert(error);
})
}
To elaborate, once I successfully get the number, I remove the parenthesis, dashes and white-space. Then, I add a "1" to the beginning. Finally, I insert colons in between each number. Then, I create an HTTP command and send it to the office phone of whoever is using CRM at the time. The user eval and HTTP message is my code. I'm showing you all of this because it was a great learning experience, and this feature really adds to the functionality.
I hope some of you find this useful.
Thanks for the help.

Do math on JSON data

I'm currently trying to do some maths on my json data. But it's not doing what I want. I made a loop so the calculation apples to every row (by the way I work with angularJS)
Here's the part of my code where I'm trying to process the data :
angular.module('recordService', []).factory('recordService', ['$http', function($http) {
var url;
var recordService = [];
recordService.getAll = function(callback) {
url = "http://localhost/app/www/database/json.php";
$http({
url: url
}).then(function(rs) {
callback(rs.data);
function logArrayElements(element, index, array) {
var thdi = rs.data[index].THDI1_avg;
console.log(thdi + 5);
}
rs.data.forEach(logArrayElements);
}, function(err) {
console.log(err)
})
}
As you can see I trying to take one element from my array and add 5 to it (it's only a test; I want to do some more advanced math later). I can see in the console.log that's its not doing what I want.
For example, if my data is 10.25, I get 10.255 when I would like 15.25. Any ideas on what I'm doing wrong?
Thanks in advance
You need to convert the JSON data into a number as #epascarello has mentioned. JSON is serialized as strings.
function logArrayElements(element, index, array) {
var thdi = Number(rs.data[index].THDI1_avg);
console.log(thdi + 5);
}
The reason you get 10.255 is, because you are adding 5 to a string.
Try:
console.log(parseFloat(thdi) + 5);
Update regarding Not a Number:
There are a couple of ways you could check whether the value is a number.
isNaN()
if(isNaN(thdi)) {
console.log("Not a number");
} else {
console.log("Is a number");
console.log(parseFloat(thdi) + 5);
}
try / catch
try{
console.log(parseFloat(thdi) + 5);
} catch(err) {
console.log("not a number");
}
Edit: Won't give desired result.
typeof
if(typeof thdi === 'number') {
console.log("Is a number");
console.log(parseFloat(thdi) + 5);
} else {
console.log("not a number");
}
Also see: How do you check that a number is NaN in JavaScript?
Note: if thdi is undefined, then isNaN() will throw an error. typeof will be able to deal with undefined.

Parse Javascript API Cloud Code afterSave with access to beforeSave values

I'm using Parse Cloud Code to do before/afterSave processing. I'd check the beforeSave value of an attribute in the afterSave hook - for example, do something when parseObj.get('status') transitions from processing => complete. I can get access to the oldVal/newVal for changed attributes in the beforeSave handler, but I can't find a way to pass the oldVal to the afterSave handler without saving as a DB field.
I tried to pass the values as an attribute to the response and response.object objects, neither makes it through to the afterSave
Parse.Cloud.beforeSave('ParseObj', function(request, response) {
var checkDirty, isDirty, parseObj, prevQ;
// request keys=["object","installationId","user","master"]
if (request.object.isNew()) {
return response.success();
} else {
parseObj = request.object;
checkDirty = ['status']; // array of all attrs to check
isDirty = [];
_.each(checkDirty, function(attr) {
if (parseObj.dirty(attr)) {
isDirty.push(attr);
}
});
console.log("isDirty=" + JSON.stringify(isDirty));
if (isDirty.length) {
prevQ = new Parse.Query('ParseObj');
return prevQ.get(parseObj.id).then(function(prevParseObj) {
var newVal, oldVal;
console.log("prevParseObj, id=" + prevParseObj.id);
oldVal = _.pick(prevParseObj.toJSON(), isDirty);
_beforeSave(parseObj, oldVal); // do something here
request.previousValues = oldVal
request.object.previousValues = oldVal
return response.success();
}, function(err) {
return response.error("parsObj NOT FOUND, parseObj.id=" + parseObj.id);
});
} else {
return response.success();
}
}
});
Parse.Cloud.afterSave('ParseObj', function(request) {
var parseObj;
// request keys=["object","installationId","user","master"],
oldVal = request.previousValues // undefined
oldVal = request.object.previousValues // also, undefined
parseObj = request.object;
_afterSave(parseObj, oldVal) // do something else here
return;
});
Any ideas?
I looked into this some more, and I ended up saving to the Parse object temporarily and removing it like this:
//Add the value you need to the object prior to saving using an "oldValue" key
yourPFObject["oldValue"] = value (this is in your SDK somewhere where the save happens)
//Get that value in afterSave in Cloud Code
var old = object.get("oldValue")
//Do whatever you need to do with "old"...
//Remove the temporary old value so it doesn't stay in the database
object.unset("oldValue")
object.save()
I hope that helps. Good luck!

Cloud code on parse.com skipping a save

I'm trying to set up a game that allows playing with random players. The code below is supposed to create a GameMessage object for both paired players. To relate both objects as part of the same game, I've decided to save the objectId of of the game made for "firstplayer" in the field "otherside" for "secondplayer" and vice-versa. For some reason (perhaps the first save of firstplayer and secondplayer isn't done before the code attempts to retrieve the objectIds, meaning there are no objectIds to get?).
Short version: Why are the "otherside" values not saving?
Parse.Cloud.define("findpartner", function(request, response) {
var User = Parse.Object.extend("_User");
var user = new User();
var currentuser = Parse.User.current();
currentuser.set("searching", 0);
var query = new Parse.Query(User);
query.equalTo("searching", 1);
query.limit(50); //limit to at most 50 users
query.find({
success: function(objects) {
var amount = objects.length;
var indexNum = Math.floor((Math.random() * amount));
var newpartner = objects[indexNum];
if (amount > 0 && newpartner.id !=currentuser.id) {
newpartner.set("searching", 0);
var Firstplayer = Parse.Object.extend("GameMessages");
var firstplayer = new Firstplayer();
var Secondplayer = Parse.Object.extend("GameMessages");
var secondplayer = new Secondplayer();
firstplayer.set("sender", currentuser.id);
firstplayer.set("receiver", newpartner.id);
firstplayer.set("sent",0);
firstplayer.set("received",0);
firstplayer.set("receiverName", newpartner.getUsername());
secondplayer.set("sender", newpartner.id);
secondplayer.set("receiver", currentuser.id);
secondplayer.set("sent",0);
secondplayer.set("received",0);
secondplayer.set("receiverName", currentuser.getUsername());
firstplayer.save().then(function(secondplayer){ <<<
return secondplayer.save(); <<<
}).then(function(firstplayer_update) { <<<
return firstplayer.save({ otherside: secondplayer.id}); <<<
}).then(function(secondplayer_update){ <<<
return secondplayer.save({ otherside: firstplayer.id}); <<<
});
newpartner.save(null, {useMasterKey: true});
}
else {
currentuser.set("searching", 1);
}
currentuser.save();
response.success(amount);
},
error: function(error) {
alert("Error: " + error.code = " " + error.message);
}
});
});
I added arrows to show where the "otherside" is. They're not in the actual code. I do not doubt the code has mistakes though, I do not know javascript. I wrote it solely by studying the parse.com documentation.
I'm not convinced that it makes sense to create these 2 independent messages and link them together, but I won't let that stand in the way of getting this working. This isn't tested, but I've refactored your code and think you should try to glean a few things from it.
// Set this up once, outside of your function, and use it everywhere
var GameMessage = Parse.Object.extend("GameMessages");
Parse.Cloud.define("findpartner", function(request, response) {
// Code defensively, make sure this function requires a user be logged in.
if (!request.user) {
console.log("non-user called findpartner");
return response.error("Unauthorized.");
}
// Get the user who called the function
var user = request.user;
// The end response is a number, apparently
var result = 0;
// The target player
var targetPlayer;
// The two messages that will be used if a match is found
var firstmsg = new GameMessage();
var secondmsg = new GameMessage();
// Create a Users query
var query = new Parse.Query(Parse.User);
query.equalTo("searching", 1);
query.notEqualTo("objectId", user.id);
query.limit(50);
// Remove public access to Find operations for Users in the Data Browser
// Use the master key to query, and use promise syntax.
query.find({ useMasterKey: true }).then(function(objects) {
result = objects.length;
// If no users were found searching, mark the user as searching and save
if (result == 0) {
user.set('searching', 1);
// Return the save promise
return user.save(null, { useMasterKey: true });
}
// Pick a random user out of the response
var indexNum = Math.floor((Math.random() * objects.length));
var targetPlayer = objects[indexNum];
// Set that user to no longer be searching and save
targetPlayer.set("searching", 0);
return targetPlayer.save(null, { useMasterKey: true }).then(function() {
firstmsg.set("sender", user.id);
firstmsg.set("receiver", targetPlayer.id);
firstmsg.set("sent", 0);
firstmsg.set("received", 0);
firstmsg.set("receiverName", targetPlayer.getUsername());
secondmsg.set("sender", targetPlayer.id);
secondmsg.set("receiver", user.id);
secondmsg.set("sent", 0);
secondmsg.set("received", 0);
secondmsg.set("receiverName", user.getUsername());
// Return the promise result of saving both messages
return Parse.Object.saveAll([firstmsg, secondmsg], { useMasterKey: true });
}).then(function(messages) {
// Set the pointers to reference each other
firstmsg.set("otherside", secondmsg.id);
secondmsg.set("otherside", firstmsg.id);
// Return the promise result of saving both messages, again
return Parse.Object.saveAll([firstmsg, secondmsg], { useMasterKey: true });
});
}).then(function() {
// All the stuff above has finished one way or the other, now we just need to
// send back the result. 0 if no match was made.
response.success(result);
}, function(error) {
response.error(error);
});
});
firstplayer.save();
secondplayer.save();
secondplayer.set("otherside",firstplayer.id); <<<
firstplayer.set("otherside",secondplayer.id); <<<
firstplayer.save();
secondplayer.save();
This is the part of code that you say not working. In parse doc you can see that .save() is a non blocking operation. Means the line firstplayer.save() goes immediately to next line(it wont block the thread for saving). So when you set id secondplayer.set("otherside",firstplayer.id) firstplayer.id is still undefined.
So if you want a synchronous logic, like save first_object then save second_object ,
you have to use call backs.
first_object.save({
success: function(saved_first_object) {
second_object.save({
success: function(saved_second_object) {
//process complete
},
failure: function(error){
}
})
},
failure: function(error) {
console.log(error);
}
})
You can also approach it using promises.
http://blog.parse.com/2013/01/29/whats-so-great-about-javascript-promises/
UPDATE: Based on question edit from OP trying promises
Try this
firstplayer.save()
.then(function(saved_firstPlayer){
firstplayer = saved_firstPlayer;
return secondplayer.save();
}).then(function(saved_secondplayer) {
secondplayer = saved_secondplayer;
return firstplayer.save({ otherside: secondplayer.id});
}).then(function(updated_firstplayer){
firstplayer = updated_firstplayer;
return secondplayer.save({ otherside: firstplayer.id});
}).then(function(updated_secondlayer){
secondplayer= update_secondplayer;
});

YDN-DB How to verify if a record exists?

I'm trying to verify if a specific record exist inside a table by a given ID. For example:
var id = 23;
db.count('products',id).done(function(count) {
if(count>0){
db.get('products',id).done(function(r) {
//Do something
});
}else{
alert('No product found');
}
});
When I try this, I get the following error: uncaught exception: null
I'd really appreciate your help Thanks!.
Your solution is almost correct.
In IndexedDB API, there is no exists method, probably because it can be emulated using count method. But count method accepts only key range, so existence test should be:
var id = 23;
db.count('products', ydn.db.KeyRange.only(id)).done(function(cnt) {
if (cnt) { // exist
} else { // no exist
}
});
Another reason, exists method don't exist in the IndexedDB api is that, get don't give error for non-existing key. So you can safely, and recommended, to do:
var id = 23;
db.get('products', id).done(function(product) {
if (product) { // exist
} else { // no exist
}
});
I would like to point out that, in these two ways to detect existence, the first method is more efficient because it avoid deserialization. So if you just need to test for existence, use first method. For retrieving a record, which may or may not exist, use second method.
EDIT:
To query a record by primary key, id, or unique secondary key, sku
/**
* #param {string} id id or sku
* #param {Function} cb callback to invoke resulting record value. If not exists in the
* database, null or undefined is returned.
*/
var getByIdOrSku = function(id, cb) {
var req = db.get('items', id);
req.done(function(item) {
if (item) {
cb(item)
} else {
db.values('items', 'SKU', ydn.db.KeyRange.only(id), 1).done(function(items) {
cb(items[0]); // may not have result
});
}
});
};
If you prefer promise way:
db.get('items', id).then(function(item) {
if (item) {
return item;
} else {
return db.values('items', 'SKU', ydn.db.KeyRange.only(id), 1).done(function(items) {
return items[0];
});
}
}).done(function(item) {
// result query as as id or SKU
console.log(item);
});

Categories

Resources