This is my function:
/* function for add transaction */
function addtransaction(user_id,status,amount,date,description){
var saved = "";
function getLastId(){
Transactions.findOne({}, {}, { sort: { '_id' : -1 } }).lean().exec(function(err, lastTrans) {
if (err) {
return 1;
}else{
return parseInt(lastTrans.id) + 1;
}
});
}
var newId = getLastId();
var newTransactions = new Transactions({
id : newId,
user_id : user_id ,
status : status ,
amount : amount ,
date : date ,
description : description
});
if (newTransactions.save()){
return true;
}else{
return false;
}
}/* end function */
And this is my console error:
Can you help me to solve this error?
enter image description here
I updated my function but there is still error!
It seems like the error is here getLastId + 1 .getLastId is a function and 1 a number, and a function cannot be cast to a number. Most likely you forgot to put the parentheses to get the result out off the function call.
Try replace getLastId + 1 with getLastId() + 1
You may missed the () in:
id: getLastId + 1
Your issue is that you're not waiting for your getLastId() to actually return since it is async. Since it is async, while getLastId() is still working, your code has already moved on to creating a new Transaction where newId is undefined since nothing has been returned. So you need to place your code dependent on newId into the callback of your Transaction.findOne() or pass in a callback to getLastId().
Just to note, your addtransaction function should take a callback function as well so you can return the outcome of newTransactions.save() to the called in an asynchronous way. I did not do this in the below code examples since I do not know how your other code is structured.
I would also say that Approach #1 below is the preferable one since its less code, doesn't involve defining getLastId() everytime addtransaction() is called and it is has less callbacks than Approach #2.
Approach #1, place logic in Transactions.findOne()
function addtransaction(user_id, status, amount, date, description) {
Transactions.findOne({}, {}, { sort: { '_id' : -1 } }).lean().exec(function(err, lastTrans) {
var newId = err ? 1 : (parseInt(lastTrans.id) + 1);
var newTransactions = new Transactions({
id : newId,
user_id : user_id ,
status : status ,
amount : amount ,
date : date ,
description : description
});
return newTransactions.save();
});
}
Approach #2, Pass in Callback
/* function for add transaction */
function addtransaction(user_id,status,amount,date,description){
var saved = "";
function getLastId(callback){
Transactions.findOne({}, {}, { sort: { '_id' : -1 } }).lean().exec(function(err, lastTrans) {
if (err) {
return callback(null, 1);
} else {
return callback(null, parseInt(lastTrans.id) + 1);
}
});
}
getLastId((err, newId) => {
var newTransactions = new Transactions({
id : newId,
user_id : user_id ,
status : status ,
amount : amount ,
date : date ,
description : description
});
return newTransactions.save();
});
}/* end function */
Its also worth noting that assigning return data directly from a function that is async isn't the proper way to construct asynchronous functions in Node.js. See this answer for the proper way to construct these types of functions.
Related
I'm having a little issue with my batch request, when the odata model is submitted and triggered, the that.readAndUpdateSercicePeriodPlans(oService).then(function(oSerciceO) in the callback is triggered before the batch return the result
As you can see using my debugger, the call back function is triggered :
but the network didn't return the result yet :
Below is the code, what I am doing wrong? :
odataMod = this.getModel("Service");
odataMod.setUseBatch(true);
var aDeffGroup = odataMod.getDeferredGroups();
//add your deffered group
aDeffGroup.push("deletionGroup");
_.forEach(periodPlanArr, function(periodPlanToDel) {
odataMod.remove('/ProjectTaskServicePeriodPlanCollection(\'' + periodPlanToDel.ObjectID + '\')/', {
groupId: "deletionGroup"
});
});
oGlobalBusyDialog.setText("Deleting Period Plans in progress");
oGlobalBusyDialog.setTitle("Updating data Model");
oGlobalBusyDialog.open();
//This trigger the batch request
odataMod.submitChanges({
// deffered group id
groupId: "deletionGroup",
success: function(oData) {
sap.m.MessageToast.show(oData.toString());
var aErrorData = sap.ui.getCore().getMessageManager().getMessageModel();
var msg = aErrorData.getData();
var oService = _.find(oNoneAssignedTaskModelData, function(oSewrv) {
return oSewrv.ObjectID === uniqueByID[0].ParentObjectID;
});
oGlobalBusyDialog.setText("Updating oModel in progress");
oGlobalBusyDialog.setTitle("Updating data Model");
// ISSUE : This below function is invoked before even the batch request is complete , why ?!
that.readAndUpdateSercicePeriodPlans(oService).then(function(oSerciceO) {
oGlobalBusyDialog.close();
//Logic USER STORY 3423: Get Internal Indicator PeriodPlan and update the employee nternal Indicator PeriodPlan
},
error: function(oError) {
var oResponse = JSON.parse(oError.response.body);
sap.m.MessageToast.show("Fehler: " + oResponse.error.message.value);
}
});
Your Chrome Filter icon will only be red if there is some value in the filter.:)
After debugging all night and drinkind redbull I've finally found the issue :
var aDeffGroup = odataMod.getDeferredGroups();
aDeffGroup.push("deletionGroup");
//I must set the deffered groups after pushing the ID or else it won't be added
this.setDeferredGroups(aDeffGroup);
I'd recommand to avoid adding same group twice - I had some issues because of that.
odataMod = this.getModel("Service");
odataMod.setUseBatch(true);
//var aDeffGroup = odataMod.getDeferredGroups();
//aDeffGroup.push("deletionGroup");
that.setModelDeferredGroup(odataMod, "deletionGroup");
// the function
setModelDeferredGroup: function (oModel, sGroup) {
if (oModel && sGroup) {
var aDeferredGroups = oModel.getDeferredGroups();
if (aDeferredGroups.indexOf(sGroup) < 0) {
aDeferredGroups.push(sGroup);
oModel.setDeferredGroups(aDeferredGroups);
}
}
}
I am trying to trigger an update within a client method (thinking to move into server later) as follows:
Meteor.methods({
// Calling this and passing in a currentSelected value = "avatar" on click
'updateSelectedDocument' : function(currentSelected) {
var current = LayoutVariations.findOne({elementID: currentSelected});
var index = current.currentIndex;
myCollection.update({_id :current._id}, {currentIndex: 2});
}
});
The .update should find the document and update that document's currentIndex property, which is an integer.
I ran the myCollection.update({_id :current._id}, {currentIndex: 2}); in the console by passing in the _id (e.g. "GRvujvgBEmem3Dp3d") and it works. It's just not updating when I call it within a method and it's not throwing any errors.
Wondering what could be the issue.
Use the $set operator in your update to replace the value of the field currentIndex with the specified :
Meteor.methods({
// Calling this and passing in a currentSelected value = "avatar" on click
'updateSelectedDocument' : function(currentSelected) {
var current = LayoutVariations.findOne({elementID: currentSelected});
var index = current.currentIndex;
myCollection.update({_id :current._id}, {$set: { currentIndex: 2 } }, function(error, affectedDocs) {
if (error) {
throw new Meteor.Error(500, error.message);
} else {
return "Update Successful";
}
});
}
});
I have a question. My intervalValue in the start function is undefined. But in the microflow function it is the value I want to have. How can I return the value in the microflow function back to the start function. I have tried basic global and return implementations of javascript, but that doesn't work and the dojo.global isn't clear enough for me know how to implement. All help is appreciated. See my code below:
start : function() {
this.addOnLoad(dojo.hitch(this, function() { //make sure the thing only starts when completely loaded!
if (this.once)
this.handle = window.setTimeout(dojo.hitch(this, function() {
this.intervalexecute();
console.log("addOnLoad " + this.intervalValue);
this.execute();
this.stopped = true;
}), this.intervalValue);
else {
this.intervalexecute();
console.log("addOnLoad " + this.intervalValue);
if (this.startatonce)
this.execute(); //invoke directly as well
this.handle = window.setInterval(dojo.hitch(this, this.execute), this.intervalValue);
}
}));
},
intervalexecute : function() {
if (this.dataobject != null && this.dataobject.getGUID && this.dataobject.getGUID())
{
//microflow set, not already calling a microflow
mx.processor.xasAction({
error : function() {
logger.error(this.id + "error: XAS error executing microflow");
},
actionname : this.intervalmicroflow,
applyto : 'selection',
guids : [this.dataobject.getGUID()],
callback : dojo.hitch(this, this.microflowresult)
});
}
},
microflowresult: function(result) {
if (result) {
this.intervalValue = dojo.fromJson(dojo.isIE ? result.xhr.responseText : result.xhr.response).actionResult;
console.log("result: " + this.intervalValue);
}
},
The reason interval value is not set is because microflowresult is an asynchronous function. Your logging statement in start is executed before microflowresult is called.
You need to have your callback do any processing on intervalValue.
I want to define a Javascript object which manages messages. Within this object, I'll need an array that I can do a push() to:
MsgObjCollection.push(MsgObj)
Essentially I am trying to fill the MsgObjCollection object with a bunch of MsgObjs. Each MsgObj has the 3 variables messagesText, timeStamp, source (sent or received).
Also, I'll need to have some methods like:
MsgObjCollection.Sent.Count // Counts the number of sent messages
MsgObjCollection.Received.Count // Counts the number of received messages
MsgObjCollection.Count // Counts the total number of messages in the object
I'm not sure how to approach this in the simplest, cleanest manner.
NOTE: In case there's any confusion, these are not static methods. I'll be creating instances of these objects using the new operator. So I will need multiple instances.
Here's a tweak on bfavaretto's answer that should get you closer to what you want:
function MsgObjCollection() {
this.sent = [];
this.received = [];
this.total = [];
this.push = function(msg) {
// Assuming msg.source is either 'sent' or 'received',
// this will push to the appropriate array.
this[msg.source].push(msg);
// Always push to the 'total' array.
this.total.push(msg);
};
};
You would use this as follows:
var coll = new MsgObjCollection();
coll.push(/* whatever */);
var sent = coll.sent.length;
var received = coll.received.length;
If you wanted, you could wrap the sent and received arrays with objects that expose a Count function instead of a length property; but that strikes me as unnecessary.
You need push, count, you might want to have all arrays methods / accesssors / iterators.
What's more, you 'll get some speed boost if you let your collection be an array.
So best solution is to inherit from array, and to
have your objects be just real arrays : nothing should be
defined on the object, everything on its prototype.
-->> You'll get the speed and all features of arrays for free.
The function looks like :
function MsgObjCollection() { /* nothing */ };
var SO_pr = ( MsgObjCollection.prototype = [] ) ;
And then, to define count, sent and received on the prototype, use Object.defineProperty not to pollute enumeration, and also to have getters/setters :
Object.defineProperty(SO_pr, 'sent', { get : function() {
var cnt = 0;
this.forEach( function(x) { if (x.source == 'Sent') cnt++; });
return cnt; } } );
Object.defineProperty(SO_pr, 'received', { get : function() {
var cnt = 0;
this.forEach( function(x) { if (x.source == 'Received') cnt++; });
return cnt; } } );
Object.defineProperty(SO_pr, 'count', { get : function() { return this.length } ,
set : function (x) { this.length = x } });
Notice that since the Msg collection's prototype is a new array, you do not pollute array's prototype when changing MsgObjCollection's prototype.
The Sent and Received property you wish are more complex : they act as a view on the underlying object.
One thing you can do is to have them return a new array built out of the right items of the original array.
I prefer, though, to build a wrapper around the original array 1) to allow modification through this view and 2) to avoid garbage creation.
The fiddle is here : http://jsfiddle.net/cjQFj/1/
Object.defineProperty(SO_pr, 'Sent',
{ get : function() { return getWrapper('Sent', this); } } ) ;
Object.defineProperty(SO_pr, 'Received',
{ get : function() { return getWrapper('Received', this); } } ) ;
function getWrapper(wrappedProp, wrappedThis) {
var indx = 0, wp=null;
// try to find a cached wrapper
while (wp = getWrapper.wrappers[indx++] ) {
if (wp.wthis === this && wp.wprop==wrappedProp) return wp.wrapper;
};
// no wrapper : now build, store, then return a new one
var newWrapper = {
get count() { return (wrappedProp=='Sent') ? wrappedThis.sent : wrappedThis.received },
unshift : function () { if (this.count == 0) return null;
var indx=0;
while (wrappedThis[indx].source != wrappedProp ) indx++;
var popped = wrappedThis[indx];
while (indx<wrappedThis.length-1) {wrappedThis[indx]=wrappedThis[indx+1]; indx++; }
wrappedThis.length--;
return popped;
}
};
getWrapper.wrappers.push({ wthis : wrappedThis, wprop : wrappedProp, wrapper : newWrapper });
return newWrapper;
};
getWrapper.wrappers = [];
Now just a little test :
var myColl = new MsgObjCollection();
myColl.push({ source : 'Sent', message : 'hello to Jhon' });
myColl.push({ source : 'Received' , message : 'hi from Kate' });
myColl.push({ source : 'Sent', message : 'hello to Kate' });
myColl.push({ source : 'Received' , message : 'Reply from Jhon' });
myColl.push({ source : 'Received' , message : 'Ho, i forgot from Jhon' });
console.log('total number of messages : ' + myColl.count);
console.log('sent : ' + myColl.sent + ' Sent.count ' + myColl.Sent.count);
console.log('received : ' + myColl.received + ' Received.count ' + myColl.Received.count);
console.log('removing oldest sent message ');
var myLastSent = myColl.Sent.unshift();
console.log ('oldest sent message content : ' + myLastSent.message);
console.log('total number of messages : ' + myColl.count);
console.log('sent : ' + myColl.sent + ' Sent.count ' + myColl.Sent.count);
console.log('received : ' + myColl.received + ' Received.count ' + myColl.Received.count);
Output : >>
total number of messages : 5
sent : 2 Sent.count 2
received : 3 Received.count 3
removing oldest sent message
oldest sent message content : hello to Jhon
total number of messages : 4
sent : 1 Sent.count 1
received : 3 Received.count 3
The annoying part is that those view properties are not arrays, but since you cannot overload [] operator, you cannot have a fully transparent view on the original array, (i.e. : myBox.Sent[i] that would be exactly the i-th sent message ) so at some point you might want to create arrays on the fly for some operations.
There are several ways to do that. One of the simplest, if you only need one instance, is an object literal:
var MsgObjCollection = {
_arr : [],
push : function(val) {
return this._arr.push(val);
},
Sent : {
Count : function() {
// ...
}
},
// etc.
};
If you need multiple instances, use a constructor, and add methods to its prototype property:
function MsgObjCollection() {
this._arr = [];
}
MsgObjCollection.prototype.push = function(val) {
return this._arr.push(val);
}
MsgObjCollection.prototype.get = function(index) {
return this._arr[index];
}
// and so on...
// USAGE:
var collection = new MsgObjCollection();
collection.push('foo');
console.log(collection.get(0));
I have a table called Subscription and another table called Client I need the gender of the Client who owns the subscription every time I make an update. Here's my update script:
function update(item, user, request) {
var subscriptionId = item.id;
var subscriptionActivitiesTable = tables.getTable("SubscriptionActivity");
var userTable = tables.getTable("User");
var activityTable = tables.getTable("Activity");
var userGender = userTable.where({id: item.UserId}).select('Gender').take(1).read();
console.log(userGender);
activityTable.where({PlanId:item.PlanId, Difficulty: item.Difficulty}).read({
success: function(results){
var startDate = item.StartDate;
results.forEach(function(activity)
{
var testDate = new Date(startDate.getFullYear(),startDate.getMonth(), startDate.getDate());
testDate.setDate(testDate.getDate() + activity.Sequence + (activity.Week*7));
subscriptionActivitiesTable.insert({SubscriptionId: subscriptionId,
ActivityId: activity.id, ShowDate: new Date(testDate.getFullYear(),
testDate.getMonth(), testDate.getDate()), CreationDate: new Date()});
})
}
});
var planWeeks = 12;//VER DE DONDE SACAMOS ESTE NUMERO
var idealWeight = 0;
if (userGender === "Male")
{
idealWeight = (21.7 * Math.pow(parseInt(item.Height)/100,2));
}
else
{
idealWeight = (23 * Math.pow(parseInt(item.Height)/100,2));
}
var metabolismoBasal = idealWeight * 0.95 * 24;
var ADE = 0.1 * metabolismoBasal;
var activityFactor;
if (item.Difficulty === "Easy")
{
activityFactor = 1.25;
}
else if(item.Difficulty === "Medium")
{
activityFactor = 1.5;
}
else
{
activityFactor = 1.75;
}
var caloricRequirement = ((metabolismoBasal + ADE)*activityFactor);
activityTable.where(function(item, caloricRequirement){
return this.PlanId === item.PlanId && this.Type != "Sport" &&
this.CaloricRequirementMin <= caloricRequirement &&
this.CaloricRequirementMax >= caloricRequirement;}, item, caloricRequirement).read({
success: function(results)
{
var startDate = item.StartDate;
results.forEach(function(activity)
{
for (var i=0;i<planWeeks;i++)
{
var testDate = new Date(startDate.getFullYear(),startDate.getMonth(), startDate.getDate());
testDate.setDate(testDate.getDate() + activity.Sequence + (i*7));
subscriptionActivitiesTable.insert({SubscriptionId: subscriptionId,
ActivityId: activity.id, ShowDate: new Date(testDate.getFullYear(),
testDate.getMonth(), testDate.getDate()), CreationDate: new Date()});
}
})
}
})
request.execute();
}
I tried the code above and clientGender is undefined. As you can see I want to use the gender to set the idealWeight.
The read() method expects a function to be passed in on the success parameter - it doesn't return the result of the query like you'd think.
Try something like this instead:
function update(item, user, request) {
var clientTable = tables.getTable("Client");
var clientGender = 'DEFAULT';
clientTable.where({id: item.ClientId}).select('Gender').take(1).read({
success: function(clients) {
if (clients.length == 0) {
console.error('Unable to find client for id ' + item.ClientId);
} else {
var client = client[0];
clientGender = client.Gender;
// since we're inside the success function, we can continue to
// use the clientGender as it will reflect the correct value
// as retrieved from the database
console.log('INSIDE: ' + clientGender);
}
}
});
// this is going to get called while the clientTable query above is
// still running and will most likely show a value of DEFAULT
console.log('OUTSIDE: ' + clientGender);
}
In this sample, the client table query is kicked off, with a callback function provided in the success parameter. When the query is finished, the callback function is called, and the resulting data is displayed to the log. Meanwhile - while the query is still running, that is - the next statement after the where/take/select/read fluent code is run, another console.log statment is executed to show the value of the clientGender field outside the read function. This code will run while the read statement is still waiting on the database. Your output should look something like this in the WAMS log:
* INSIDE: Male
* OUTSIDE: Default
Since the log shows the oldest entries at the bottom, you can see that the OUTSIDE log entry was written sometime before the INSIDE log.
If you're not used to async or functional programming, this might look weird, but as far as I've found, this is now node works. Functions nested in functions nested in functions can get kind of scary, but if you plan ahead, it probably won't be too bad :-)