-1

I need to add multilines conditionally in an ES6 Template Literal based on some conditions and have extra indentations deleted on every line.

Code:

const reactComponentJSX = `
  ${condition1? '<Menu/>' : ''}
  ${condition2? '<p>Welcome to my app</p>' : ''}
  ${condition3? '<Body/>' : ''}
  ${condition4? '<h1>Good bye</h1>' : ''}
`;

Actual Output:

Let's assume condition1 and condition4 are false so following JSX would be printed.

// unnecessary new line
// unnecessary new line
  <p>Welcome to my app</p>
// unnecessary new line
  <h1>Good bye</h1>

Notice the unnecessary indents in each non empty line.

Expected Output:

Show lines without indentation and not print new line with false condition.

<p>Welcome to my app</p>
<h1>Good bye</h1>

Note: I am writing template for a JSX file. So, you can consider the problem statement as conditional writing JSX tags in render function, conditionally importing libraries in the JSX file, e.t.c.

Vinay Sharma
  • 3,291
  • 4
  • 30
  • 66
  • 1
    Move where the interpolations start, so the newlines are in the expression not the string. – jonrsharpe Nov 29 '20 at 13:22
  • 1
    Does this answer your question? [es6 multiline template strings with no new lines and allow indents](https://stackoverflow.com/questions/40672651/es6-multiline-template-strings-with-no-new-lines-and-allow-indents) – jonrsharpe Nov 29 '20 at 13:23
  • 3
    Template literal interprets multiline literally. So, one way to do it is to put all of them in one line, and add a new line as escaped character conditionally. – BlackMath Nov 29 '20 at 13:26
  • No that's not a duplicate, with the answer for this duplicate target, the output will be `text2text4` and not the expected `text2\ntext4` – Nino Filiu Nov 29 '20 at 13:29
  • @BlackMath yes that can be done but statements are pretty long. So as to maintain code readable I have to keep them this way. – Vinay Sharma Nov 29 '20 at 13:30
  • @VinaySharma Have you tried `${condition && 'text'}` instead of `${condition ? 'text' : ' '}`? – BlackMath Nov 29 '20 at 13:31
  • @BlackMath that prints false – Vinay Sharma Nov 29 '20 at 13:32
  • @jonrsharpe that does not answer. It would print `text2` and `text4` in single line rather than each new in new line. – Vinay Sharma Nov 29 '20 at 13:33
  • It does answer, because it stops you having newlines in the template itself; if you still want newlines in the interpolated values they have to be *in the values*. – jonrsharpe Nov 29 '20 at 13:52
  • Just don't use a template literal. Use an array instead, conditionally put lines in it, and then render these by joining them with linebreaks. – Bergi Nov 29 '20 at 20:47
  • @Bergi your solution defies the requirement of using template literals. – Vinay Sharma Nov 30 '20 at 16:03
  • @here A suggestion for the downvote will be appreciated. – Vinay Sharma Nov 30 '20 at 16:04
  • @VinaySharma No, I'm challenging your assumption that you need to use template literals. It's really unclear why that would be a hard requirement. – Bergi Nov 30 '20 at 16:06
  • @Bergi because I am generating a complex JSX component and prefer to write it in form of template literals to make it much readable. Let's say component is 100's of lines long. Will it be a scalable solution to write each line of that component with line break characters and tab space into an array? – Vinay Sharma Nov 30 '20 at 16:52
  • @VinaySharma If you want to scale better, I would suggest generating more but smaller, less complex components. Hundreths of lines is just too long. But back to the question, I was not referring to the writing the *whole* component template without template literals, but only those conditionally generated lines. And no, you wouldn't put line breaks and tabs inside that array, you'd add them programmatically in the end, this is the whole point. This might go as far as creating an abstract syntax tree, and then pretty-printing that. If you show us more of your actual code, we can help you better – Bergi Nov 30 '20 at 17:09
  • @Bergi hmm.. I understand your paradigm now – Vinay Sharma Dec 01 '20 at 05:38

2 Answers2

0

// dummy conditions and texts
const conditions = (new Array(10)).fill().map(() => Math.random() < 0.5);
const components = (new Array(10)).fill().map((_,i) => `<Component${i}/>`);

// create your content with map and join
const content = conditions
  .map((condition, i) => condition ? components[i]+'\n' : null)
  .filter(template => template !== null)
  .join('')
console.log(content);
Nino Filiu
  • 16,660
  • 11
  • 54
  • 84
0

You can create a tagged template that clears empty newlines:

const clearEmpty = (strings, ...exps) => 
  // trim the strings, and join with the expressions - substitute empty strings for undefined/null expressions.
  // replace empty lines with empty arrays that will be absorbed by flatMap
  strings.flatMap((s, i) => `${s.trim()}${exps[i] ?? ''}` || []) 
    .join('\n') // join remaining strings with empty lines
    .trim(); // trim the spaces before and after
  
const condition1 = true;
const condition2 = false;
const condition3 = true;
const condition4 = false;

const reactComponentJSX = clearEmpty`
  ${condition1? '<Menu/>' : ''}
  ${condition2? '<p>Welcome to my app</p>' : ''}
  ${condition3? '<Body/>' : ''}
  ${condition4? '<h1>Good bye</h1>' : ''}
`;

console.log(reactComponentJSX);
Ori Drori
  • 183,571
  • 29
  • 224
  • 209