Unexpected comma using map()
Asked Answered
Z

4

132

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?

Zicarelli answered 22/8, 2017 at 8:5 Comment(4)
The map() function is ok. The problem should come from somewhere elseMarceline
Looks like you are using some kind of templating language here; which one?Ado
I'm using plain JS (ES2015) here (just a jQuery selection to the body and to append the element). Added a snippet to the description.Zicarelli
@CBroe: Those are ES2015+ template literals.Swell
C
298

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>
Conservancy answered 22/8, 2017 at 8:11 Comment(2)
Wow, can't believe I forgot to join() my array. Thanks haha!Gilli
I wonder how this accepted answer is in the same minutes with other belowCham
S
39

.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>
Schnook answered 22/8, 2017 at 8:11 Comment(4)
how does map returns array? we are already telling it to return a template literal right?Guiscard
Can you clarify what you're asking? .map always returns an array. We can't tell it to return a template literal and aren't doing so here.Schnook
``` ${description.map( function(work) { return <li>${work}</li> } ``` here we are returning the template literlal <li>${work}</li> right? so how is it again converting into array?Guiscard
You're looking at the return from the callback, not from array.map itself. The array.map method creates a new array, then iterates through the existing array, calls your callback function on each element, and pushes onto the new array whatever value your callback returns. Finally, it returns the new array. Here is a simple example you can try in your browser's dev tools: let a = [5,10,15]; let b = a.map( function(x) { return -x; }); console.log(a); console.log(b); As you can see, the return statement in the callback returns a number, but map collects all those into a new array.Schnook
O
14

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>
Oppose answered 2/7, 2020 at 8:10 Comment(0)
M
1

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

Maestricht answered 25/6, 2021 at 2:37 Comment(1)
This is better suited as a comment, rather than an answer. As it doesn't clarify on the OP`s original problem. But rather introduces different syntax.Thief

© 2022 - 2024 — McMap. All rights reserved.