I've an array with a list of elements and I'm trying to append this list to an HTML element using template strings:

var description = [
  'HTML & CSS',
  'Javascript object-oriented programming',
  'Progressive Web apps (PWAs)',
  'Website Performance Optimization',
  'Webpack and Gulp workflows',
  'Fullstack React.js',
  'Web Components',
  'Responsive web design',
  'Sketch design',
  'GraphQL and Relay'
]

$('body').append(
  `
  <div class="description">
    <ul>
      ${description.map(
        function(work) {
          return `<li>${work}</li>`
        }
      )}</ul>
  </div>
  `
)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

As a result I get an unexpected comma between each list element. (You can see this when you run the code snippet above.)

How can I avoid this?


Solution 1:

Explanation

template literals use the toString() method which by default joins the returned array by map with a ,.
To avoid this "problem" you can use join('')

Code

var description = [
  'HTML & CSS',
  'Javascript object-oriented programming',
  'Progressive Web apps (PWAs)',
  'Website Performance Optimization',
  'Webpack and Gulp workflows',
  'Fullstack React.js',
  'Web Components',
  'Responsive web design',
  'Sketch design',
  'GraphQL and Relay'
]

$('body').append(
  `
  <div class="description">
    <ul>
     ${
        description.map(function(work) {
          return `<li>${work}</li>`
        }).join('')
      }
    </ul>
  </div>
  `
)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Solution 2:

.map() returns an array. You probably want to return a string containing the array elements concatenated together. You can do that with .join(''):

var description = [
  'HTML & CSS',
  'Javascript object-oriented programming',
  'Progressive Web apps (PWAs)',
  'Website Performance Optimization',
  'Webpack and Gulp workflows',
  'Fullstack React.js',
  'Web Components',
  'Responsive web design',
  'Sketch design',
  'GraphQL and Relay'
]

$('body').append(
  `
  <div class="description">
    <ul>
      ${description.map(
        function(work) {
          return `<li>${work}</li>`
        }
      ).join('') /* added .join('') here */}</ul>
  </div>
  `
)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Solution 3:

As others have pointed out (which I'm going to repeat for completeness sake), Array.prototype.map returns a new array which contains the elements that are altered in the function that is passed to it.

When you concatenate an array to a string (which is what is happening here), it will convert the array to a string as well. And when an array is converted to a string, it is automatically joined using commas.

const arr = ['<a>', '<b>'];

console.log(arr + ""); // <a>,<b>

Besides using .join() to explicitly pass an empty string as the separator, you can also replace the .map() with a Array.prototype.reduce to reduce the array to a single value.

description.reduce((acc, work) => acc + `<li>${work}</li>`, '')

So the complete code would look like this:

var description = [
  'HTML & CSS',
  'Javascript object-oriented programming',
  'Progressive Web apps (PWAs)',
  'Website Performance Optimization',
  'Webpack and Gulp workflows',
  'Fullstack React.js',
  'Web Components',
  'Responsive web design',
  'Sketch design',
  'GraphQL and Relay'
]

$('body').append(
  `
  <div class="description">
    <ul>
     ${
        description.reduce((acc, work) => acc + `<li>${work}</li>`, '')
      }
    </ul>
  </div>
  `
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Solution 4:

For simple your code, i just use like this: ${description.map((work) => <li>${work}</li>).join('')}