TiagoM
TiagoM

Reputation: 3526

How to create a conditional string that's based on two variables without a bunch of if elses (JavaScript)

I am trying to create a custom string to be shown to the user, which is based on two variables.

Here is the example that I am trying to build:

let url1;
let url2;
if (containsData1) {
  url1 = "http://test";
}

if (containsData2) {
  url2 = "http://test2";
}

let finalString = '';
if (url1 && url2) {
  finalString = 'The url 1 is ' + url1 + ' and url 2 is ' + url2;
} else if (!url1 && url2) {
  finalString = 'There isnt data for url1. Url2 is ' + url2;
} else if (url1 && !url2) {
  finalString = 'The url 1 is ' + url1 + '. There isnt data for url2';
} else if (!url1 && !url2) {
  finalString = 'There isnt data for url1. There isnt data for url2';
}

However I would like to this in a proper way, without using this bunch of if elses, any suggestions on how to accomplish this?

Thanks.

Upvotes: 3

Views: 1209

Answers (4)

VLAZ
VLAZ

Reputation: 28983

It's better to treat that as two different conditional strings and then join them together:

let string1;
if (url1) {
  string1 = 'The url 1 is ' + url1 + '.';
} else {
  string1 = 'There isnt data for url1.';
}

let string2;
if (url2) {
   string2 = 'Url2 is ' + url2;
} else {
  string2 = 'There isnt data for url2';
}

let finalString = string1 + string2;

This allows you to reason about the resulting string in a more straight forward way than considering each possible case at once. With only two variables, you have 4 possible outcomes, with 4 you'd have 16.

Separating each variable means that you don't need to care what the other possibilities are when you generate each substring.

You can further make that simpler to think about by using templates. In that case you can separate the string generation logic elsewhere so you focus on different things in different areas

  • figuring out what each individual message should be
  • figuring out how to display them

For example you might want to standardise the messages and have something like:

function makeSubMessage(url, name) {
  if (url) {
    return `The $[name} is ${url}`;
  } else {
    return `No data for ${name}`;
  }
}
/* ... */
let string1 = makeSubMessage(url1, "Url1");

Which will allow you to more easily swap what the format of the messages is without having to touch how they are then presented.

When you're presenting them, you might want to have each message on a separate line, than simply one string, so the result need not rely on what the submessages are:

function(urls) {
  let finalString = "";
  for (let i = 0; i < urls.length; i++) {
    let subMessage = makeSubMessage(urls[i], "Url" + (i + 1));
    finalString += subMessage;
    finalString += "\n"
  }

  return finalString;
}

Or you can change this implementation entirely:

function(urls) {
  let finalString = urls
    .map((url, i) => makeSubMessage(url, "Url" + (i + 1)))
    .join("\n")

  return finalString;
}

or change to display them as HTML bulletpoints, perhaps:

function(urls) {
  let finalString = urls
    .map((url, i) => makeSubMessage(url, "Url" + (i + 1)))
    .map(subMessage => `<li>${subMessage}</li>`)
    .join("<br/>")

  return `<ul>${finalString}</ul>`;
}

Or anything else. Point being that the concerns are now separated.

Upvotes: 0

Oli
Oli

Reputation: 872

I'm sure we could get even more precise with the ternary statements:

let url1 = containsData1;
let url2 = containsData2;

let finalString = url1 ? `The url 1 is ${url1}` : 'There is no data for url 1';

if (url1 && url2) {finalString += ` and url 2 is ${url2}.`}
if (!url2) {finalString += '. There is no data for url2.'}

Upvotes: 0

Kobe
Kobe

Reputation: 6446

You could use ternary statements:

let url1;
let url2;
url1 = "http://test";
url2 = "http://test2";
let finalString = (url1 ? 'The url 1 is ' + url1 : 'There isnt data for url1.') +
  (url1 && url2 ? ' and t' : ' T') +
  (url2 ? 'he url 2 is ' + url2 : 'There isnt data for url2.');

console.log(finalString)

Upvotes: 3

PRDeving
PRDeving

Reputation: 669

1st - Use ES6 string templates

let url1;
let url2;
if (containsData1) {
  url1 = "http://test";
}

if (containsData2) {
  url2 = "http://test2";
}

let finalString = '';
if (url1 && url2) {
  finalString = `The url 1 is ${ url1 } and url 2 is ${ url2 }`;
} else if (!url1 && url2) {
  finalString = `There isnt data for url1. Url2 is ${ url2 }`;
} else if (url1 && !url2) {
  finalString = `The url 1 is ${ url1 }. There isnt data for url2`;
} else if (!url1 && !url2) {
  finalString = 'There isnt data for url1. There isnt data for url2';
}

2nd - unify and extract

const urls = {
  url1: containsData1 ? "http://test" : null,
  url2: containsData2 ? "http://test" : null,
}

const assertData = name => urls[name] ? `${name} is ${urls[name]}` : `isnt data for ${name}`

let finalString = `${assertData('url1')}. ${assertData('url2')}`

Upvotes: 0

Related Questions