better solution about JS nesting if statement - javascript

Let's say there are 3 divs in my html.
Id's are:
stepone
steptwo
stepthree
I want first to load in data which is json from server on stepone div, if the return is '1' then print good on stepone div.
Then load in data on steptwo div, the data is json as well. So basically this is the process and the following is my code:
$(document).ready(function(){
var loadingone = $.post("stepone.php");
.done(function(dataone){
objone = JSON && JSON.parse(dataone) || $.parseJSON(dataone); //get json return from server
if (objone.status == "1") {
$("#stepone").html("good");
var loadingtwo = $.post("steptwo.php")
.done(function(datatwo){
objtwo = JSON && JSON.parse(datatwo) || $.parseJSON(datatwo);
if (objtwo.status == "1"){
$("#steptwo").html("good");
}
else
{
$("#steptwo").html("bad");
}
});
}
else
{
$("#stepone").html("message" + objone.codeurl);
}
});
});
So as you can see the code contains nested if statement and it doesn't look very clear. I am wondering if there is a better solution for this? thx
===updata===
here's the code after i edited, is it right?
var loadingone = $.post("stepone.php");
.done(function(dataone){
objone = JSON && JSON.parse(dataone) || $.parseJSON(dataone);
if (objone.status != "1"){
$("#stepone").html("bad" + objone.codeurl")
}
else{
$("#stepone").html("good");
var loadingtwo = $.post("steptwo.php");
.done(function(datatwo){
objtwo = JSON && JSON.parse(datatwo) || $.parseJSON(datatwo);
if (objtwo.status != "1"){
$("#steptwo").html("bad");
}
else
{
$("#steptwo").html("good");
}
}
}

Negate your expressions.
Rather than following a pattern like:
if A {
if B {
if C {
do stuff
}
else error C
}
else error B
}
else error A
Try this:
if !A {
error A
return
}
if !B {
error B
return
}
if !C {
error C
return
}
do stuff
This way, you keep the errors with their respective conditions, and you avoid deep nesting.

Related

Page reading 2 different If-Statements as the same

I'm running into a pretty confusing situation here:
if ((a.length == 0 || b === null)) {
this.noNotif = true;
console.log("1");
}
if (a.length > 0 || b === null) {
this.newNotif = true;
// this.noNotif = false;
console.log("2");
} else {
if (a.length === b.length) {
console.log("No New Notifications");
this.noNotif = true;
} else {
console.log("New notifications");
this.newNotif = true;
}
Console logging a.length returns 0 and 'b' is null
However, the issue is that somehow both of the first two if-statements' conditions are being met. noNotif and newNotif both display a Vue components and both are showing up currently.
Some background information about a & b
'a' is supposed to be data from an API that is fetched on page load. 'b' is supposed to be a localStorage object array
The first if-statement deals with a new user who has no API data or anything stored in LocalStorage
The second if-statement handles when the user does have data in the API, but nothing in LS yet.
The First nested if-statement is if the data from the API matches the LS data
The nested else-statement is if the API data is different (longer) than what's in LS
EDITED:
It turns out you also didn't put an "else" statement between the two. They're both triggering because they're both registering the || b = null.
if ((a.length == 0 || b === null)) {
this.noNotif = true;
console.log("1");
} else if (a.length > 0 || b === null) {
this.newNotif = true;
// this.noNotif = false;
console.log("2");
} ...

Unable to print out a property in json

I am dynamically adding a new property(object) into the existing object.
Here is my code:
.then(transactionDetails => {
console.log(transactionDetails);
if(transactionDetails != null){
transactionDetails["nextDueDate"];
for(var i = 0; i < transactionDetails.length; i++){
if(transactionDetails[i].customers_installment_detail.installment1_isPaid === false){
nextDueDate = {
installment1_dueAmount:transactionDetails[i].customers_installment_detail.installment1_dueAmount,
installment1_dueDate:transactionDetails[i].customers_installment_detail.installment1_dueDate
}
}else if(transactionDetails[i].customers_installment_detail.installment2_isPaid === false){
nextDueDate = {
installment2_dueAmount:transactionDetails[i].customers_installment_detail.installment2_dueAmount,
installment2_dueDate:transactionDetails[i].customers_installment_detail.installment2_dueDate
}
}else if(transactionDetails[i].customers_installment_detail.installment3_isPaid === false){
nextDueDate = {
installment3_dueAmount:transactionDetails[i].customers_installment_detail.installment3_dueAmount,
installment3_dueDate:transactionDetails[i].customers_installment_detail.installment3_dueDate
}
}else if(transactionDetails[i].customers_installment_detail.installment4_isPaid === false){
nextDueDate = {
installment2_dueAmount:transactionDetails[i].customers_installment_detail.installment4_dueAmount,
installment2_dueDate:transactionDetails[i].customers_installment_detail.installment4_dueDate
}
}
transactionDetails[i]["nextDueDate"] = nextDueDate;
}
res.json({response:transactionDetails});
}else{
res.json({response:"No active transaction."});
}
})
I am dynamically adding nextDueDate. I am able to print out the value in console by typing transactionDetails[0].nextDueDate but however when I try to print it out the whole object in JSON, nextDueDate is missing and just could not be printed out. Any reasons ?
It is due to Sequelize issue according to this thread:
Add Property to Object that is returned by Sequelize FindOne
I fixed this by adding a virtual column in my model.
nextDueDate: Sequelize.VIRTUAL

Why am I getting TypeError on length property

Getting this error:
TypeError: Cannot read property 'length' of undefined
For this code:
var getSuggestions = function(query) {
searchService.getSuggestions(query).then(function(es_return){
var suggestions = es_return.suggest.phraseSuggestion;
var results = es_return.hits.hits;
if (suggestions.length > 0) {
$scope.autocomplete.suggestions = suggestions;
}
else {
$scope.autocomplete.suggestions = [];
}
if (results.length > 0) {
$scope.autocomplete.results = results;
}
else {
$scope.autocomplete.results = [];
}
if (suggestions.length > 0 || results.length > 0) {
$scope.showAutocomplete = true;
}
else {
$scope.showAutocomplete = false;
}
});
};
Specifically on the first if statement and I don't see why? Need some fresh eyes to show me what I'm doing wrong.
I think you need some better null handling. With Suggestion.length > 0 null cannot be evaluated with >, right? So probably use boolean instead (or both).
if (Suggestion.length){
//do stuff
}
It looks like your es_return.suggest.phraseSuggestion is undefined.You can try like this:
if(suggestions != undefined)
{
if (suggestions.length > 0) {
$scope.autocomplete.suggestions = suggestions;
}
else {
$scope.autocomplete.suggestions = [];
}
}
Try to debug the code from the developer console.
Probably you should es_return.hits.hits remake to es_return.hits.
In your case es_return.hits.hits or suggestions are not an array.
After I drilled down on this more, I noticed that I had an issue with the ES query that I was using for the ac code. It was actually just a typo. Where I had phrasesuggestion in the js, I had phrase_suggestion in the json query for ES, once I fixed that - it worked! Thanks for your efforts.

true == false evaluates to true somehow?

I've been working to scrape some webpage that is using the OWASP CRSFGuard project for protection. The library seems to be causing one of my requests to get a 401 so I started digging through their code and noticed the following;
function isValidDomain(current, target) {
var result = false;
/** check exact or subdomain match **/
if(current == target || current == 'localhost') {
result = true;
} else if(true == false) {
if(target.charAt(0) == '.') {
result = current.endsWith(target);
} else {
result = current.endsWith('.' + target);
}
}
return result;
}
From what I can tell, there must be instances where this code is executed; result = current.endsWith('.' + target);. Given true == false is inherently false, how would the code reach that statement? Is this some JS oddity (I know we're not using the strict === equality, but seriously...)?
Answer: It will never reach that code block.
function isValidDomain(current, target) {
var result = false;
/** check exact or subdomain match **/
if (current == target || current == 'localhost') {
result = true;
} else if (true == false) {
if (target.charAt(0) == '.') {
result = current.endsWith(target);
} else {
result = current.endsWith('.' + target);
}
}
return result;
}
var trueFalse = document.getElementById('trueFalse');
trueFalse.innerHTML = isValidDomain('true', 'false') ? 'WTF!' : 'All is good in the JS World';
trueFalse.addEventListener('click', function(e) {
trueFalse.innerHTML = (true == false) ? 'WTF!' : 'All is good in the JS World Still';
});
<div id="trueFalse"></div>
I would say that Blazemonger is most likely correct.
That else if probably had some other condition at some point, and for whatever reason, they decided they didn't want that block of code to execute anymore, so they changed the condition to something that is always false.
It's also not entirely uncommon to see programmers use 1 === 0 as an indication for false. Why they would want to do this is anybody's guess.

Nicer way to get nested object attributes

Often in a response from a remote API call, I receive nested objects:
var response = {
data : {
users : [
{
name : 'Mr. White'
}
]
}
}
I want to check whether the first user's name is 'Mr. White', and would naturally want to write something like.
var existed = response.data.users[0].name === 'Mr. White'
However I cannot be sure if all the objects are present, so to avoid exceptions instead I end up writing:
var existed = response && response.data && response.data.users && response.data.users[0].name === 'Mr. White'
Is there a nicer way to do this? Another ugly option that comes to mind is:
var existed = false;
try {
var existed = response.data.users[0].name === 'Mr. White';
} catch(e) { }
In addition to vanilla javascript, I usually have underscore.js and jquery available too.
Edit:
Oops, noticed I asked a dupe of javascript test for existence of nested object key.
An interesting option based on those answers is:
var existed = (((response || {}).data || {}).users || [{}])[0].name === 'Mr. White';
You could hide this naughty try/catch block inside a function like this one :
function resolve(root, path){
try {
return (new Function(
'root', 'return root.' + path + ';'
))(root);
} catch (e) {}
}
var tree = { level1: [{ key: 'value' }] };
resolve(tree, 'level1[0].key'); // "value"
resolve(tree, 'level1[1].key'); // undefined
More on this : https://stackoverflow.com/a/18381564/1636522
I would use the try catch approach but wrap it in a function to hide the ugliness.
Instead of a try/catch, this should be done via checking whether each level in the object is defined or not.
go for
if(typeof(response)!="undefined"
&& typeof(response.data)!="undefined"
&& typeof(response.data.users)!="undefined"
&& typeof(response.data.users[0])!="undefined"
&& typeof(response.data.users[0].name)!="undefined"
) {
//executes only if response.data.users[0].name is existing
}
Here is a function which I used in one of my projects http://jsfiddle.net/JBBAJ/
var object = {
data: {
users: [
{
firstName: "White"
},
{
firstName: "Black"
}
]
}
}
var read = function(path, obj) {
var path = path.split(".");
var item = path.shift();
if(item.indexOf("]") == item.length-1) {
// array
item = item.split("[");
var arrayName = item.shift();
var arrayIndex = parseInt(item.shift().replace("]", ""));
var arr = obj[arrayName || ""];
if(arr && arr[arrayIndex]) {
return read(path.join("."), arr[arrayIndex]);
} else {
return null;
}
} else {
// object
if(obj[item]) {
if(path.length === 0) {
return obj[item];
} else {
return read(path.join("."), obj[item]);
}
} else {
return null;
}
}
}
console.log(read("data.users[0].firstName", object)); // White
console.log(read("data.users[1].firstName", object)); // Black
console.log(read("data.test.users[0]", object)); // null
The idea is to pass your path as a string along with your object. The idea was to prevent the throwing of an exception and receive just null as result of the path is wrong. The good thing is that the function works with every path and you don't need to write long if statements.

Categories

Resources