Both find calls inside the ifs have callbacks that start by function(e, docs).
What would be a clean way to refactor it to be DRYer?
Thanks.
if (connection_id == null) {
id_connectionsCollection.find({}, {}, function (e, docs) {
if (e) {
return callback(e);
}
var connectionDetails = null;
if (docs == null || docs.length == 0) {//if no connections found, use default from config
connectionDetails = defaultConnectionDetails
}
else {
connectionDetails = docs[0];//just get the first one
}
return callback(null, connectionDetails);
});
}
else {
id_connectionsCollection.find({name: connection_id}, {sort: {updated_at: -1}}, function (e, docs) {
if (e) {
return callback(e);
}
var connectionDetails = null;
if (docs == null || docs.length == 0) {
connectionDetails = defaultConnectionDetails;
}
else {
connectionDetails = docs[0];//just get the first one
}
return callback(null, connectionDetails);
});
}
The most obvious way to DRY your code is to extract your callback to a named function that can be passed as your callback on the last arg of your find method:
// Can probably think of a better name here...
doCallback = function(e, docs) {
if (e)
return callback(e);
var connectionDetails = null;
if (docs == null || docs.length == 0)
connectionDetails = defaultConnectionDetails;
else
connectionDetails = docs[0];//just get the first one
return callback(null, connectionDetails);
}
if (connection_id == null)
id_connectionsCollection.find({}, {}, doCallback);
else
id_connectionsCollection.find({name: connection_id}, {sort: {updated_at: -1}}, doCallback);
Related
I am currently implementing a javascript function to judge if user id and name matches or not.
function name_match(user_id, user_realname) {
var dbref = firebase.database().ref();
var namesref = dbref.child("names");
namesref.on("value", function(snapshot) {
snapshot.forEach(i => {
if(i.key == user_id && i.child("realname").val() == user_realname) {
return true;
}
});
});
return false;
}
However, regardless of input, it will initially return false. I think this is because it will go to "return false" while firebase data is loading.
So, even if eventually returns true, since the first-time return value is false, it causes a problem in like this (in another function).
function name_match2() {
var user_id = document.getElementById("user-id").value;
var user_realname = document.getElementById("user-realname").value;
if(!name_match(user_id, user_realname)) return -1;
return 0;
}
And it will return -1.
Can you explain how to solve this problem?
As explained by Daniel in the comment, outer function never returns true. The async solutions could be these :)
function name_match(user_id, user_realname) {
return new Promise(function (resolve, reject) {
var dbref = firebase.database().ref();
var namesref = dbref.child("names");
namesref.on("value", function(snapshot) {
var matched = false;
snapshot.forEach(i => {
if(i.key == user_id && i.child("realname").val() == user_realname) {
matched = true;
}
});
if (matched) {
resolve()
} else {
reject()
}
});
});
}
On the other side of calling function
name_match('userId', 'userName').then(function(){
//matched
}, function(){
//unmatched
});
Other way would be to use Callbacks:
function name_match(user_id, user_realname, cb) {
var dbref = firebase.database().ref();
var namesref = dbref.child("names");
namesref.on("value", function(snapshot) {
var matched = false;
snapshot.forEach(i => {
if(i.key == user_id && i.child("realname").val() == user_realname) {
matched = true;
}
});
cb(matched);
});
}
In this case:
name_match('userId', 'userName', function(matched) {
console.log(matched);
})
Here is a small adaptation of Suryapratap solution, using the once() method, which
"Listens for exactly one event of the specified event type, and then stops listening.", and
Returns a Promise
... instead of using the on() method which sets a listener.
function name_match(user_id, user_realname) {
var dbref = firebase.database().ref();
var namesref = dbref.child("names");
return namesref.once('value').then(function(snapshot) {
var matched = false;
snapshot.forEach(i => {
if(i.key == user_id && i.child("realname").val() == user_realname) {
matched = true;
}
});
return matched;
});
}
I have a function that inside a function. I want the parent function to return an updated object (after the loop ends), currently, it returns undefined because the parent function returns nothing, only the child function function(items) returns data. How can I make the parent function returns updated return_data? Thanks a lot.
reportParser: (report) => {
const return_data = {
"click": "[id^='AUTOGENBOOKMARK_75_'].style_12",
"clicker": "[id^='AUTOGENBOOKMARK_74_'].style_12",
"openning": ".style_25 > .style_24",
"openner": ".style_25 > .style_24",
"name": "[id^='AUTOGENBOOKMARK_7_'].style_12",
"subject": "[id^='AUTOGENBOOKMARK_9_'].style_12",
"audience": "[id^='AUTOGENBOOKMARK_11_'].style_12",
"sent_mails": "[id^='AUTOGENBOOKMARK_20_'].style_12",
"send_date": "[id^='AUTOGENBOOKMARK_32_'].style_12",
"cancel_subscription_click": ".style_25 > .style_24",
"cancel_subscription_clicker": ".style_25 > .style_24"
};
let remaining_keys = Object.keys(return_data).length;
for (let key in return_data) {
if (return_data.hasOwnProperty(key)) {
html2json.parse(report, function () {
return this.map(return_data[key], function ($item) {
return $item.text();
});
}).done(function (items) {
if (key === "click" || key === "clicker" || key === "sent_mails") {
items[0] = items[0].replace(/,/g, "");
return_data[key] = parseInt(items[0]);
} else if (key === "openning") {
items[items.length - 2] = items[items.length - 2].replace(/,/g, "");
return_data[key] = parseInt(items[items.length - 2]);
} else if (key === "openner") {
items[items.length - 3] = items[items.length - 3].replace(/,/g, "");
return_data[key] = parseInt(items[items.length - 3]);
} else if (key === "cancel_subscription_click") {
return_data[key] = parseInt(items[13]) + parseInt(items[18]) + parseInt(items[23]);
} else if (key === "cancel_subscription_clicker") {
return_data[key] = parseInt(items[11]) + parseInt(items[16]) + parseInt(items[21]);
} else {
return_data[key] = items[0];
}
remaining_keys--;
if (remaining_keys === 0) {
return_data["click"] -= return_data["cancel_subscription_click"];
return_data["clicker"] -= return_data["cancel_subscription_clicker"];
delete return_data.cancel_subscription_click;
delete return_data.cancel_subscription_clicker;
logger.debug(return_data);
return return_data;
}
}, function (err) {
// Handle error
});
}
}
}
The execution would be function -> object init -> wait for loop to update object -> return object
You can either use a callback function or write this function as a promise.
Callback is a function you will pass into your function to execute after the data is done.
For the callback function:
https://developer.mozilla.org/en-US/docs/Glossary/Callback_function
reportParser = (report, callback) => {
//... process data
html2json.parse(report, function() {
//...
}).done(function(items) {
//after you have done process and get return_data, use callback
callback(return_data);
})
}
So when you using reportParser:
reportParser(report, function(return_data) {
//whatever you want to do with return_data
})
For the promise:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
reportParser = (report) => {
return new Promise(function(resolve, reject) {
//... process data
html2json.parse(report, function() {
//...
}).done(function(items) {
//after you have done process and get return_data, use callback
resolve(return_data);
})
})
}
And when you using reportParser function:
reportParse(report).then(return_data => {
//whatever you want to do with return_data
})
Seems html2json.parse return a Promise, so in your case you have to return a Promise as well in your parent function
reportParser: (report) => {
const return_data = {
"click": "[id^='AUTOGENBOOKMARK_75_'].style_12",
"clicker": "[id^='AUTOGENBOOKMARK_74_'].style_12",
"openning": ".style_25 > .style_24",
"openner": ".style_25 > .style_24",
"name": "[id^='AUTOGENBOOKMARK_7_'].style_12",
"subject": "[id^='AUTOGENBOOKMARK_9_'].style_12",
"audience": "[id^='AUTOGENBOOKMARK_11_'].style_12",
"sent_mails": "[id^='AUTOGENBOOKMARK_20_'].style_12",
"send_date": "[id^='AUTOGENBOOKMARK_32_'].style_12",
"cancel_subscription_click": ".style_25 > .style_24",
"cancel_subscription_clicker": ".style_25 > .style_24"
};
let remaining_keys = Object.keys(return_data).length;
/* here return a Promise */
return new Promise((resolve, reject) => {
for (let key in return_data) {
if (return_data.hasOwnProperty(key)) {
html2json.parse(report, function () {
return this.map(return_data[key], function ($item) {
return $item.text();
});
}).done(function (items) {
if (key === "click" || key === "clicker" || key === "sent_mails") {
items[0] = items[0].replace(/,/g, "");
return_data[key] = parseInt(items[0]);
} else if (key === "openning") {
items[items.length - 2] = items[items.length - 2].replace(/,/g, "");
return_data[key] = parseInt(items[items.length - 2]);
} else if (key === "openner") {
items[items.length - 3] = items[items.length - 3].replace(/,/g, "");
return_data[key] = parseInt(items[items.length - 3]);
} else if (key === "cancel_subscription_click") {
return_data[key] = parseInt(items[13]) + parseInt(items[18]) + parseInt(items[23]);
} else if (key === "cancel_subscription_clicker") {
return_data[key] = parseInt(items[11]) + parseInt(items[16]) + parseInt(items[21]);
} else {
return_data[key] = items[0];
}
remaining_keys--;
if (remaining_keys === 0) {
return_data["click"] -= return_data["cancel_subscription_click"];
return_data["clicker"] -= return_data["cancel_subscription_clicker"];
delete return_data.cancel_subscription_click;
delete return_data.cancel_subscription_clicker;
logger.debug(return_data);
/* RESOLVE THE PROMISE */
resolve(return_data);
return return_data;
}
}, function (err) {
// Handle error
/* REJECT THE PROMISE ON ERROR */
reject(err);
});
}
}
});
}
than you will able to use your function as a regular Promise
reportParser(report).then((data) => {
// Work with the returned data
}).catch((err) => {
// Handle errors
})
Why am I getting Could not complete the operation due to error 80043200 sometimes while getting Outlook item property (for example, Subject) in email Compose mode?
Call stack:
Error
at n.prototype.execute (appsforoffice.microsoft.com/lib/1.1/hosted/outlook-win32-16.02.js:11:86635)
at u.DDA.OutlookAppOm.prototype.callOutlookDispatcher (appsforoffice.microsoft.com/lib/1.1/hosted/outlook-win32-16.02.js:11:150300)
at u.DDA.OutlookAppOm.prototype.invokeHostMethod (appsforoffice.microsoft.com/lib/1.1/hosted/outlook-win32-16.02.js:11:150169)
at u.DDA.OutlookAppOm.prototype._standardInvokeHostMethod$i$0 (appsforoffice.microsoft.com/lib/1.1/hosted/outlook-win32-16.02.js:11:148443)
at r.ComposeSubject.prototype.getAsync (appsforoffice.microsoft.com/lib/1.1/hosted/outlook-win32-16.02.js:11:190544)
We use following code for getting a field from an Outlook item:
sfMailApp.OfficeManager.prototype._reloadField = function (name, defaultValue) {
var deferred = $.Deferred();
defaultValue = defaultValue || '';
var item = this.getItem();
if (item.isFake) {
deferred.resolve('');
return deferred.promise();
}
var field = item[name];
if (field && this._isComposeMode && field.getAsync) {
var _this = this;
try {
field.getAsync(function (result) {
if (result.status === Office.AsyncResultStatus.Succeeded) {
_this[name] = _this._processOfficeData(result.value) || defaultValue;
deferred.resolve(_this[name]);
}
else {
_this._onError(result);
deferred.reject();
}
});
} catch (e) {
deferred.reject();
}
} else {
this[name] = this._processOfficeData(field) || defaultValue;
deferred.resolve(this[name]);
}
return deferred.promise();}
Code for getItem function:
sfMailApp.OfficeManager.prototype.getItem = function () {
var item = Office && Office.context && Office.context.mailbox && Office.context.mailbox.item ? Office.context.mailbox.item : null;
if (!item) {
item = {
isFake: true
}
}
return item;}
One more error we're getting sometimes while trying to get user identity token:
{"name":"AccessRestricted","message":"Internal protocol error: -2147467259'.","code":9017 }
How should we handle that?
How do I iterate over a asynchronous function in nodejs stopping depending on callback return?
Example:
suppose I have following function
var fn1 = function(i, callback){
// code here
callfunction(i, function(err, p2){
if(err) throw err;
if(something) return callback(true);
else return callback(false);
});
}
I need to iterate and call for i=1,2,3,... until my callback returns false.
I tried using async whilst, but I do not think it can helps me, because the test function also needs callback, and the function for test and iteratee are same, I cannot call twice.
If I understand your problem correctly. What about some recursion
const maxTries = 10;
// just a stupid counter to run a be able to change return value
let numberOfCalls = 0;
const asyncCall = () => {
if (numberOfCalls === 9) {
return Promise.resolve(false);
}
numberOfCalls += 1;
return Promise.resolve();
};
function iterate(calls = 0) {
if (maxTries === calls) {
return Promise.resolve();
}
return asyncCall().then(value => {
if (value === false) {
return value;
}
return iterate(calls + 1);
});
}
iterate().then(result => {
if (result === undefined) {
//to many tries
}
console.log('result', result);
});
I'm trying to check if a string is in a JSON object with javascript. I don't know if it is possible or I have to convert something. Here is the part of the code with the if statement in which I want to check if data.userName (the string) is in users (the JSON object)
function validation() {
var userName_login = document.getElementById("username").value;
var password_login = document.getElementById("password").value;
var data = {
userName: userName_login,
password: password_login
};
doJSONRequest("GET", "/users/", null, data, function(users) {
if (data.userName) {
}
})
}
And the doJSONRequest function is:
function doJSONRequest(method, url, headers, data, callback) {
if (arguments.length != 5) {
throw new Error('Illegal argument count');
}
doRequestChecks(method, true, data);
var r = new XMLHttpRequest();
r.open(method, url, true);
doRequestSetHeaders(r, method, headers);
r.onreadystatechange = function() {
if (r.readyState != 4 || (r.status != 200 && r.status != 201 && r.status != 204)) {
return;
} else {
if (isJSON(r.responseText))
callback(JSON.parse(r.responseText));
else
callback();
}
};
var dataToSend = null;
if (!("undefined" == typeof data) && !(data === null))
dataToSend = JSON.stringify(data);
r.send(dataToSend);
}
function checkForValue(json, value) {
for (key in json) {
if (typeof (json[key]) === "object") {
return checkForValue(json[key], value);
} else if (json[key] === value) {
return true;
}
}
return false;
}
check if Json string has value in JS
Just try to parse it using JSON.parse, if the parse was successful return true else return false:
function isJSON(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}