Javascript Comparing Booleans - javascript

Currently, I have an mongo database that keeps track of answers users submit. When a user makes an input for an answer they already did, that is yes or no I want to check to see if there answer has changed. The issue is this only working half of the time.
Below I have a sails service called Questions Service which is called from the Questions Controller when a user send an answer to the node.js server.
QuestionServer.js
var ObjectID = require('mongodb').ObjectID;
module.exports = {
submitAnswer: function(tokenKey, questionId, answer, done) {
User.findOne({tokenKey: tokenKey}).exec(function (err, findOneRecord){
if(findOneRecord) {
var qId = ObjectID(questionId);
QuestionsAnswered.findOrCreate({question: qId, user: findOneRecord.id}).exec(function createFindCB(error, createdOrFoundRecord){
if(error) {
done(error, findOneRecord, null);
}else if(createdOrFoundRecord){
var oldAnswerChanged = QuestionService.submitAnswerCheck(createdOrFoundRecord.answer, answer);
console.log("Old Changed Answer = " + oldAnswerChanged);
createdOrFoundRecord.answer = answer;
createdOrFoundRecord.save(function(saveErr) {
QuestionService.submitCount(questionId, answer, oldAnswerChanged, done);
});
}
});
}
});
},
submitAnswerCheck: function(recordAnswer, answer) {
console.log("recordAnswer = " + recordAnswer);
console.log("answer = " + answer);
recordAnswer = Boolean(recordAnswer);
answer = Boolean(answer);
if(recordAnswer != answer){
return true;
}
return false;
}
}
As you can see from my code above in my submitAnswerCheck function I want to make sure that the booleans being passed to this function are always primitives and never boolean objects.
Below you will find the output of all the console logs going to the server.
Additional note about the output below, changing != to !== does not change the out from the console. Answers below were still the same.
Output to console:
recordAnswer = true
answer = true
Old Changed Answer = false
recordAnswer = true
answer = false
Old Changed Answer = false
recordAnswer = false
answer = false
Old Changed Answer = true
recordAnswer = false
answer = true
Old Changed Answer = true
recordAnswer = true
answer = true
Old Changed Answer = false
What I would like to see is example output 2 and 4 both return true for the "Old Changed Answer", but what seems to be happening is that whenever the recordAnswer is false the submitAnswerCheck is always returning true.
Lastly here is the model that is saving the boolean to mongodb:
QuestionsAnswered.js
module.exports = {
attributes: {
question: {
model: "question",
required: true
},
user: {
model: "user",
required: true
},
answer: {
type: "boolean",
boolean: true
}
}
};
I am not sure if I am miss understanding the difference between boolean primitives and boolean objects or if there is something else I am missing when setting up a boolean in my model. Have other people been having this problem when comparing boolean in javascript/sails.js?

Found the problem
1st off as this article explains using Boolean function is very dangerous because it turns out JavaScript is pretty aggressive about type coercion. Which means you can't relay on the Boolean function to convert your variables to primitives.
From this I found out that Postman was sending my answer booleans as string example:
debug: answer = 'true'
The solution was as simple as checking if answer equals 'true' as shown below:
Correct way (QuestionController.js):
module.exports = {
answer: function(req, res) {
var tokenKey = req.param("tokenKey");
var questionId = req.param("questionId");
var answer = (req.param("answer") == 'true');
QuestionService.submitAnswer(tokenKey, questionId, answer, function(err, yes, no){
return res.json({
countYes: yes,
countNo: no,
err: err
});
});
}
};
Incorrect way:
module.exports = {
answer: function(req, res) {
var tokenKey = req.param("tokenKey");
var questionId = req.param("questionId");
var answer = req.param("answer");
QuestionService.submitAnswer(tokenKey, questionId, answer, function(err, yes, no){
return res.json({
countYes: yes,
countNo: no,
err: err
});
});
}
};

Related

How to make query parameter values case-insensitive

I want an endpoint that is a GET method to /book with a query parameter called name. If the name is 'scott', I want to return "Cracking the Coding Interview," but if it's 'SCOTT,' I want to do the same thing. Why does this not work?
app.get('/book', function (req, res) {
let result = ''
const name = req.query.name.toString().toLowerCase()
if (name === "scott") {
result = "Cracking the Coding Interview"
} else if (name === "enoch") {
result = "The Pragmatic Programmer"
} else {
result = "Good Old Neon"
}
res.send(result);
});
req.query.name could be undefined, and so we must unwrap it to access that value; search up "swift optionals" if this terminology is confusing.

condense if, else JS with similar condition rules

trying to find a way to condense this. wasnt sure of the best way to do it. basically if criteria is met i display an alert with a parameter that is the message. i was thinking of maybe trying it in function. this is part of a larger function react component. i was also thinking if i could find a way to condense the else if's i could use a ternary. thanks in advance for the assistance.
const handleUpdatePassword = () => {
const allFilled = !reject(passwords).length;
const passwordsMatch = newPassword === conPassword;
const isDifferent = curPassword !== newPassword;
const meetsPasswordRequirements = validatePassword();
const usesName = isUsingName();
const usesUserID = isPartOfUserID();
const isValidPassword = meetsPasswordRequirements && isDifferent;
if (allFilled) {
if (!isDifferent) {
Alert.alert(difPassWord);
} else if (!passwordsMatch) {
Alert.alert(noMatch);
} else if (!meetsPasswordRequirements) {
Alert.alert(pasReqs);
} else if (usesName || usesUserID) {
Alert.alert(pasName);
}
} else {
Alert.alert(fieldNotComplete);
}
if (isValidPassword) {
changePasswordPost(
{
userId,
curPassword,
newPassword
},
partyId
);
}
};
You can create an array of objects for your validation rules, each containing a function which returns a boolean indicating whether that validation passes, and a string with the error message to display.
Then loop over the rules array and alert the message for the first rule that returns false. If they all return true, do the post.
You can split each if statement into a function, then chain them. For example
// here we make a closure to validate, and return a Promise
// condition can be a function
const validate = (condition, error) => ()=> new Promise((res, rej)=>{
if(condition()){
res();
}else{
rej(error);
}
});
const handleUpdatePassword = () => {
const validateFieldsComplete = validate(
()=>!reject(passwords).length,
fieldNotComplete
);
const validateDifPassword = validate(
()=> curPassword !== newPassword,
difPassWord
);
// ...
validateFieldsComplete()
.then(validateDifPassword)
.then(...)
.catch(Alert.alert)
}
It would be much cleaner with pipe. You can take a look at ramda. Or if you are intrested in functional way, you might consider using Monad.
I'd recommend DRYing up the Alert.alert part since all branches have that in common, and just come up with an expression that evaluates to the alert message. Compactness isn't always everything, but if you want it, then nested conditional operators can fit the bill. I'm also rearranging your conditions so that it can be a flat chain of if/elses:
const message
= reject(passwords).length ? fieldNotComplete
: curPassword === newPassword ? difPassWord
: newPassword !== conPassword ? noMatch
: !validatePassword() ? pasReqs
: (isUsingName() || isPartOfUserID()) ? pasName
: null;
const isValid = !message;
if (!isValid) {
Alert.alert(message);
}
(feel free to use any other sort of code formatting pattern; nested conditionals always look awkward no matter which pattern you use, IMO.)
Edit:
Also inlined conditionals which will short-circuit evaluation and make it even more compact.
I'd setup a validations object that has the tests and error messages and then loop over it. If validation fails, it'll throw the last validation error message. Using this method, you only have to maintain your tests in one place and not mess with a block of conditional statements.
const handleUpdatePassword = () => {
const validations = {
allFilled: {
test() {
return newPass && oldPass
},
error: 'Must fill out all fields'
},
correct: {
test() {
return curPass === oldPass
},
error: 'Incorrect password'
},
[...]
}
const invalid = () => {
let flag = false
for (let validation in validations) {
if (!validations[validation].test()) {
flag = validations[validation].error
}
}
return flag
}
if (invalid()) {
Alert.alert(invalid())
} else {
changePasswordPost(
{
userId,
curPass,
newPass
},
partyId
)
}
}
hi everyone this was the method i used for a solution
const messages = [
{
alertMessage: difPassWord,
displayRule: different()
},
{
alertMessage: noMatch,
displayRule: match()
},
{
alertMessage: pasReqs,
displayRule: validatePassword()
},
{
alertMessage: pasName,
displayRule: !isUsingName() || !isPartOfUserID()
}
];
if (allFilled) {
const arrayLength = messages.length;
for (let i = 0; i < arrayLength; i++) {
if (messages[i].displayRule === false) {
Alert.alert(messages[i].alertMessage);
}
}

Firebase: Run a query synchronously

I am trying to set some user data depending on the no.of users already in my USERS COLLECTION. This even includes a userId which should be a number.
exports.setUserData = functions.firestore.document('/users/{documentId}')
.onCreate(event => {
return admin.firestore().collection('users')
.orderBy('userId', 'desc').limit(1)
.get().then(function(snapshot) {
const user = snapshot.docs[0].data();
var lastUserId = user.userId;
var userObject = {
userId: lastUserId + 1,... some other fields here
};
event.data.ref.set(userObject, {
merge: true
});
});
});
One issue I noticed here, quickly adding 2 users result in those documents having the same userId may be because the get() query is asynchronous?
Is there a way to make this whole setUserData method synchronous?
There is no way to make Cloud Functions run your function invocations sequentially. That would also be quite contrary to the serverless promise of auto-scaling to demands.
But in your case there's a much simpler, lower level primitive to get a sequential ID. You should store the last known user ID in the database and then use a transaction to read/update it.
var counterRef = admin.firestore().collection('counters').doc('userid');
return db.runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(counterRef).then(function(counterDoc) {
var newValue = (counterDoc.data() || 0) + 1;
transaction.update(counterRef, newValue);
});
});
Solution
var counterRef = admin.firestore().collection('counters').doc('userId');
return admin.firestore().runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(counterRef).then(function(counterDoc) {
var newValue = (counterDoc.data().value || 0) + 1;
transaction.update(counterRef, {
"value": newValue
});
});
}).then(t => {
admin.firestore().runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(counterRef).then(function(counterDoc) {
var userIdCounter = counterDoc.data().value || 0;
var userObject = {
userId: userIdCounter
};
event.data.ref.set(userObject, {
merge: true
});
});
})
});

Weird bug with Accounts.onCreatedUser

Here is a weird bug I am having. First here is my code
User = {};
User._defaults = {
emails : [],
enabled : true
}
User.defaults = function(){
var defaults = _.clone(User._defaults);
return _.extend(defaults,{
createdAt : new Date()
});
}
Accounts.onCreateUser(function(options, user){
console.log(User.defaults());
// returns {emails: [ { address: 'francis#domain.com', verified: true } ], enabled: true}
_.defaults(user, User.defaults());
user.emails.push(user.services.linkedin.emailAddress);
return user;
});
As you can see, when I call User.defaults() it returns an object with the emails array filled with the email address of the previous new use.
But what is even weirder, is that when I do this :
Accounts.onCreateUser(function(options, user){
console.log(User._defaults, User.defaults());
user.enabled = true;
user.emails = [];
user.createdAt = new Date();
// _.defaults(user, User.defaults());
user.emails.push(user.services.linkedin.emailAddress);
return user;
})
The logged User.defaults() actually return an object with the emails array empty.
Anyone has an idea what can cause this ??
Thanks !!
This would have to do with the Underscore clone function. If you read the docs.
Create a shallow-copied clone of the provided plain object. Any nested
objects or arrays will be copied by reference, not duplicated.
The important part is the shallow copy. Your array is not an actual copy, it's just a reference. So you are always referring to the same array every time.
I would do the following.
User = {};
User.defaults = function(){
return {
emails : [],
enabled : true,
createdAt : new Date()
}
}

Javascript iterating through a set of properties

Hi I have created a function object that contains a set of properties.This is what I have:
function LoginModelDTO(data) {
var self = this;
self.UserName = ko.observable(data.UserName).extend({
minLength: {
params: 25,
message: "Username should have at least 25 chars"
},
required: {
message: "Username is required"
},
maxLength: {
params: 50,
message: "Username should not have more then 50 chars"
},
trackChanges: null
});
self.Password = ko.observable(data.Password).extend({
stringLength: {
params: 25,
},
required: {
message: "Password is required"
},
trackChanges: null
});
self.RememberMe = ko.observable(data.RememberMe).extend({
trackChanges: null
});
self.isValid = ko.computed(function () {
var bool = self.FirstName.isValid() &&
self.Username.isValid() &&
self.Password.isValid() &&
self.RememberMe() &&
return bool;
});
}
What I would like is to be able to find a way to iterate over each property and ask if it's valid without writing every property every time because I also have to write a similar structure like self.isValid for hasChanges , revertChanges etc.
Furthermore I will need to create other similar objects to LoginModelDTO that have around 30-35 properties.This will result in alot of code and a bigger javascript file then needed.
Is there any way I can iterate only threw the properties and check if they are valid? isValid should be skipped
eis gave you part of it in the comments, and Misters gave you a part in the answer, but here's it all together:
var allValidatablesAreValid = true;
for (var property in self)
{
if (self.hasOwnProperty(property) && self[property]["isValid"]) {
allValidatablesAreValid = allValidatablesAreValid && self[property].isValid();
}
// You can add an early bail out here:
// if (!allValidatablesAreValid) { break; }
}
WELL for..in statement can help you:
var obj = {
pro1:"hello",
pro2:function(){
//code here
},
etc:function(){
}//...
}
for(var property in obj)
{
if(obj.hasOwnProperty(property))
{
console.log(property)//display the name of the property and of course the access
}
}
And to access to the values of the property you can do this:
for(var property in obj)
{
if(obj.hasOwnProperty(property))
{
console.log(obj[property])//display the value of the property(in case that you need it)
}
}
Since the question was related to the knockout-validation library, I thought I would show how to do this using the library, itself.
self.isValid = ko.computed(function () {
return ko.validatedObservable(self).isValid()
});
See the above link for more information.

Categories

Resources