Is There A Way to Avoid Nested Switch Statements - javascript

I am working on a React project using nested switch statements to route the user depending on their selection. The first case has two more nested switch statements. The second case has one nested switch statement. Is there another way I could do this without all the nested switch statements? Any help is greatly appreciated.
clickConfirm = () => {
switch (this.props.serviceType) {
case 'car_service':
switch (this.props.loadType) {
case 0:
switch (this.props.photoMode) {
case 0:
this.props.push('/payment/');
break;
case 1:
this.props.push('/payment/');
// capture image here
break;
case 2:
this.props.push('/capture/');
break;
}
break;
case 1:
switch (this.props.photoMode) {
case 0:
this.props.history.push('/address/');
this.props.setToPhoneNumber(false);
break;
case 1:
this.props.history.push('/address/');
this.props.setToPhoneNumber(false);
// capture image here
break;
case 2:
this.props.push('/capture/');
break;
}
break;
case 2:
this.props.history.push('/phone/');
this.props.setToPhoneNumber(true);
break;
}
break;
case 'phone_service':
switch (this.props.photoMode) {
case 0:
this.props.history.push('/address/');
break;
case 1:
this.props.history.push('/address/');
// capture image here
break;
case 2:
this.props.history.push('/capture/');
break;
}
break;
}
};

You can store the data in an object like this:
const SERVICES = {
'car_service': {
0: {
0: ()=> {
this.props.push('/payment/');
}
}
}
}
Then you can replace the switch part with:
clickConfirm = () => {
SERVICES[this.props.serviceType][this.props.loadType][this.props.photoMode]();
}

I don't suggest this, seems like your component should maybe take in the option directly or otherwise be broken up instead of combined in the way it is.
But without knowing your use-case or why you're "pushing to props"(?), purely to "flatten" your condition, you could combine the various values and enumerate the known combinations.
NOTE: I haven't tested this or attempted to map this to your conditions exactly, but the general idea...
const combined = [this.props.serviceType, this.props.photoMode, this.props.loadType || 'NA'].join('|');
switch (combined) {
case 'car_service|0|0':
this.props.push('/payment/'); break;
case 'car_service|1|0':
this.props.push('/payment/'); break; // capture image here
case 'car_service|2|0':
this.props.push('/capture/'); break;
case 'car_service|0|1':
this.props.push('/address/'); this.props.setToPhoneNumber(false); break;
case 'car_service|1|1':
this.props.push('/address/'); this.props.setToPhoneNumber(false); break; // capture image here
case 'car_service|2|1':
this.props.push('/capture/'); break;
case 'car_service|0|2':
case 'car_service|1|2':
case 'car_service|2|2':
this.props.history.push('/phone/'); this.props.setToPhoneNumber(true); break;
case 'phone_service|0|NA':
this.props.history.push('/address/'); break;
case 'phone_service|1|NA':
this.props.history.push('/address/'); break; // capture image here
case 'phone_service|2|NA':
this.props.history.push('/address/'); break;

Related

Javascript switch case keeps skipping to the default case

My Switch case keeps on going to default.
The condition is from the intersectionWord which outputs a specific keyword from an array which matches up to a word in the trigger word array aka an intersectionWord.
const TriggerWord = ["weather", "add", "multiply", "divide", "subtract", "hi", "hello",];
const intersectionWord = TriggerWord.filter(element => request.requestContent.includes(element));
And the objective was to pass that trigger word into the switch statement to evaluate if any of those cases match up. If they do match up it should output an alert. But currently it just seems to go straight to the default case every time.
I don't know where it is going wrong.
switch (intersectionWord) {
case TriggerWord[0].toString:
alert("Checking the weather");
break;
case TriggerWord[1].toString:
alert("Doing the math");
break;
case TriggerWord[2].toString:
alert("Doing multiplication");
break;
case TriggerWord[3].toString:
alert("Doing the division");
break;
case TriggerWord[4].toString:
alert("Doing the subtraction");
break;
case TriggerWord[5].toString:
alert("Just saying Hello");
break;
case TriggerWord[6].toString:
alert("Just saying Hello");
break;
default:
alert("I couldn't find a TriggerWord");
}
As noted in the comments, there are two problems with your code:
You're missing the () after .toString so it will call the function; also, it's not necessary to use .toString(), since they're already strings.
intersectionWord is an array, so it will never be equal to any of the strings in TriggerWords.
Instead of the switch/case statement, consider using an object:
const messages = {
weather: "Checking the weather",
add: "Doing the math",
multiply: "Doing multiplication",
...
}
Then you can loop over intersectionWords, looking up the corresponding message:
intersectionWords.forEach(word => alert(messages[word]))
Or you could combine them all into a single message:
let actions = intersectionWords.map(word => messages[word]).join(", ");
if (actions) {
alert(actions);
} else {
alert("No matching activity");
}

How to correctly loop querySelectorAll for hyperlink translation (JavaScript)

Hello!
Am working on an author's hyperlink translation in several languages.
Could someone help me correctly loop querySelectAll which translates some text for all elements collected by it, because it only translates the first hyperlink and not them all.
switch (pLang) {
case "lv":
document.querySelectorAll('[title="John Davis publikācijas"]').innerHTML = "Džons Deivis";
break;
case "ru":
document.querySelectorAll('[title="Записи John Davis"]').innerHTML = "Джон Дэйвис";
break;
}
You could use a forEach to modify all the elements instead of just the first one:
switch (pLang)
{
case "lv":
[... document.querySelectorAll('[title="John Davis publikācijas"]')].forEach((element)=>
{
element.innerHTML = "Džons Deivis";
});
break;
case "ru":
[... document.querySelectorAll('[title="Записи John Davis"]')].forEach((element)=>
{
element.innerHTML = "Джон Дэйвис";
});
break;
}

How to simplify multiple if statements javascript?

I have multiple conditions to check. I have to add icons based on the conditions, Then I need to change the background color based on some other set of conditions. I am using if statement. This is my code.
JSON:
{
"date": "2017-05-12",
"a": false,
"b": true,
"c": true,
"d": false,
"status": "active"
}
Javascript:
if (date != -1) {
//do something
if (a) {
//Add icon a
}
if (b) {
//Add icon b
}
if (c) {
//Add icon c
}
if (d) {
//Add icon d
}
}
if(status == "active"){
//Background Green
}
else if (status == "onhold"){
//Background Yellow
}
else if (status == "inactive"){
//Background Red
}
else{
//Backgeound Grey
}
How do I simplify it?
The first half of you code looks fine.
For the second half of your code you should make use of a switch statement. These replace the if-else statements you are using and decide what to do when certain "cases" occur. For example:
switch(status) {
case 'active':
//background green
break;
case 'onhold':
//background yellow
break;
case 'inactive':
//background red
break;
default:
//background grey
break;
}
My idea is:
var icons = {
a: 'a.png',
b: 'b.png',
c: 'c.png',
d: 'd.png',
}
if (date != -1) {
Object.keys(icons).forEach(function(key) {
if (data[key]) {
//Add icon icons[key]
}
});
}
var statusColors = {
active: 'Green',
onhold: 'Yellow',
inactive: 'Grey',
}
//Background statusColors[status]
I think it is pretty good as it is. Is is better to have understandable code than complex code that does exactly the same thing.
You don't have to do
if (a === true)
as it's equivalent to
if ( a )
There is no way to "simplify" it, but you can try to use switch statement instead:
switch (status) {
case 'active':
// active
break;
case 'onhold':
// onhold
break;
case 'inactive':
// inactive
break;
default:
console.log('default');
}
You can even "group" some conditions:
switch (status) {
case 'active':
case 'onhold':
// active AND onhold case
break;
case 'inactive':
// inactive
break;
default:
console.log('default');
}
More about switch statement -> https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/switch
For Status variable you can use switch but for the first condition you have to use if-else statements I think.
switch (status) {
case "active":
//Background Green
break;
case "onhold":
//Background Yellow
break;
case "inactive":
//Background Red
break;
default:
//Backgeound Grey
}
a?setIconA():b?setIconB:c?setIconC;d?setIconD
and
status == "active" ? setGreen() : status == "onhold": setYellow()
and so on.
Your question doesn't quite give the details of the actions in each case, but if they're very similar, and there's a match between the property name and whatever action you need to take, you can use loops.
['a','b','c','d'].forEach(function (k)
{
if (objectFromJSON[k])
{
addIcon(k);
}
});
For the second part, it's slightly more complex as you have status names that don't match the color. You can either:
define CSS classes with those status names, and use the status name to set the class:
CSS:
.status-active
{
background: green;
}
.status-onhold
{
background: yellow;
}
.status-inactive
{
background: red;
}
JS:
theHTMLobject.classList.addClass('status-'+objectFromJSON.status);
use an object's properties (or a Map) to convert the status into a color
Do you mean "simplify" or do you mean "shorten" - because the two are almost mutually exclusive (shorter code is often not simpler!)
Your code is clear, and understandable. But it is a bit verbose, and can get much more complex as things grow. Sometimes it is better to shorten and the risk of making it a bit harder to understand.
You could consider things like a map between the status and the appropriate color
var backgroundStatusMap = {
"active":"green",
"onhold": "yellow",
"inactive": "red"
};
var backgroundColor = backgroundStatusMap[json.status];
Things like this can be added to easier if you as add new statuses - without having to trawl for the right place to put a new if.. condition.
Similarly, you could create a map for the booleans-to-icons
var iconMap = {
"a":"icon_a.png",
"b": "icon_b.png"
};
function getIcon(json, prop){
if(json[prop])
return iconMap[prop];
return null;
}
var iconA = getIcon(json,"a");
var iconB = getIcon(json,"b");

JS JQVMap hovercolor regions

I'm new to JS and have no idea how to get this to work. I'm trying to color multiple regions if one of them is hovered by the mouse. I'm using a switch case to get all the regions together. And this seems to work so far, because I'm getting out my test line. I'm sure I'm just missing on a tiny thing here. I appreciate any help!
jQuery(document).ready(function () {
var red = '#E20079', blue = '#009EE0', yel = '#FFFA00';
jQuery('#vmap').vectorMap({
map: 'usa_en',
backgroundColor: '#383838',
enableZoom: false,
showTooltip: true,
selectedColor: null,
onRegionOver: function(event, code, region){
switch(code) {
case 'wa': case 'or': case 'ca': case 'nv': case 'id':
case 'mt': case 'wy': case 'ut': case 'az': case 'nm':
case 'co': case 'ne': case 'ks': case 'sd': case 'nd':
case 'mn': case 'wi': case 'ia': case 'il': case 'ak':
case 'hi':
//this output is working fine
document.getElementById("demo").innerHTML = code;
//but it won't change the color!!
hoverColor: 'blue';
break;
case 'mo': case 'ok': case 'tx': case 'ar': case 'la':
case 'ms': case 'al': case 'ga': case 'fl': case 'tn':
case 'ky': case 'sc': case 'in': case 'sc':
hoverColor: 'yel';
break;
case 'mi': case 'oh': case 'nc': case 'va': case 'wv':
case 'pa': case 'de': case 'nj': case 'ny': case 'ct':
case 'ri': case 'ma': case 'vt': case 'nh': case 'me':
case 'md': case 'dc':
hoverColor: 'red';
break;
}
},
onRegionClick: function(code){
switch(code) {
case 'wa': case 'or': case 'ca': case 'nv': case 'id':
case 'mt': case 'wy': case 'ut': case 'az': case 'nm':
case 'co': case 'ne': case 'ks': case 'sd': case 'nd':
case 'mn': case 'wi': case 'ia': case 'il': case 'ak':
case 'hi':
window.open("http://www.google.com");
break;
case 'mo': case 'ok': case 'tx': case 'ar': case 'la':
case 'ms': case 'al': case 'ga': case 'fl': case 'tn':
case 'ky': case 'sc': case 'in': case 'sc':
window.open("http://www.yahoo.com");
break;
case 'mi': case 'oh': case 'nc': case 'va': case 'wv':
case 'pa': case 'de': case 'nj': case 'ny': case 'ct':
case 'ri': case 'ma': case 'vt': case 'nh': case 'me':
case 'md': case 'dc':
window.open("http://www.example.com");
break;
}
}
});
});
I refactored a bit your code to be less redundant, in some way.
My proposal is as follows:
jQuery(document).ready(function () {
// Group the codes of each state in the desired macro-areas
var areas = [['wa','or','ca','nv','id','mt','wy','ut','az','nm','co','ne','ks','sd','nd','mn','wi','ia','il','ak','hi'],
['mo','ok','tx','ar','la','ms','al','ga','fl','tn','ky','sc','in'],
['mi','oh','nc','va','wv','pa','de','nj','ny','ct','ri','ma','vt','nh','me','md','dc']],
// Assign links to areas
links = {0: "http://www.google.com", 1: "http://www.yahoo.com", 2: "http://www.example.com"},
// Define colors
red = '#E20079', blue = '#009EE0', yel = '#FFFA00',
// Assign colors to areas
colors = {0: blue, 1: yel, 2: red},
// Prepare container for hover colors
hoverColors = {};
(function () {
// Build a ready-to-use hoverColors list
areas.forEach(function(members, area) {
members.forEach(function(state) {
hoverColors[state] = colors[area];
});
});
})();
// Used in mouse enter and mouse leave handlers
function toggleAreaHiglight(code, action){
var vMap = $('#vmap');
areas.forEach(function(members) {
if(members.indexOf(code)>-1) {
members.forEach(function(state) {
if(state != code) vMap.vectorMap(action, state);
});
}
});
}
// Initialize the map
$('#vmap').vectorMap({
map: 'usa_en',
backgroundColor: '#383838',
enableZoom: false,
showTooltip: true,
selectedColor: null,
hoverColors: hoverColors,
onRegionOver: function(event, code, region){
toggleAreaHiglight(code, 'highlight');
},
onRegionOut: function(event, code, region){
toggleAreaHiglight(code, 'unhighlight');
},
onRegionClick: function(event, code, region){
var link = links[$(areas).map(function(i) {
if(this.indexOf(code)>-1) return i;
})[0]];
if(link) window.open(link);
}
});
});
There are two parts which needs some explanation:
hoverColors: i'm just preparing in advance an object which will
contain the association between the code of a state and the needed
hover color. The result then looks like this:
{
ak: "#009EE0",
al: "#FFFA00",
ar: "#FFFA00",
... all other states
wv: "#E20079",
wy: "#009EE0"
}
toggleAreaHighlight: why skipping the current region code in the toggle highlight function?
if(state != code) $('#vmap').vectorMap(action, state);
Highlighting and un-highlighting the current state (region) under the mouse pointer is already built-in, and and so, therefore, there is no need to handle it twice.
BTW, an additional note:
in your second area, you declared South Carolina two times, maybe this is a typo, but anyway, to avoid nasty unwanted side effects, each code must be just only once in the areas.

Why isn't my switch block (switching on $(e.target) .attr("class")) working?

I am trying to figure out why this code doesn't work..
All i want is to have simple event delegation to assign one event listener.
it only alerts, it doesn't animate.
Please let me know whats wrong here:
$(document).ready(function() {
var img = $("img");
$("span").click(function(e){
var targetClicked = $(e.target).attr('class');
//the alert works fine
alert(targetClicked)
switch(targetClicked){
// i deleted the rest of the cases
case d:img.stop(false,true);
break;
case e:img.slideDown().animate({"width":200, height:200, opacity:0.4,});
break;
//nothings works here as well
case f:alert("hi");
break;
}
});
});
What are d and e in your switch statement case conditions? The way you're code is written right now, they're being treated as variables and your code is probably blowing up with a "'d' is undefined" error.
If you want to switch on the class names "d" and "e", then you need to use the class names as strings:
switch (targetClicked) {
case "d":
//...
break;
case "e":
// ...
break;
}

Categories

Resources