alex
alex

Reputation: 7601

Why does the following map function produce undefined objects?

I have an array context.buildingFields.finished that looks like this:

[{ name: 'a' type: 'text', value: '1' }, { name: 'b' type: 'file', value: '2' }] 

And I have a function that loops through that array to create a new one context.createPanoramasPayload with only the fields of type file:

function handleCreatePanoramas (uploadedPhoto, context, callback) {
    const panoramasFields = context.buildingFields.finished
    context.createPanoramasPayload = panoramasFields.map(field => {
      if (field.type !== 'file') return
      return {
        name: 'index',
        value: uploadedPhoto
      }
    })
    callback(context.createPanoramasPayload)
  }
}

I thought I would produce something like this (say with only one field of type file):

[{ name: 'b' type: 'file', value: '2' }] 

However, what I'm getting is something like this:

[undefined, { name: 'b' type: 'file', value: '2' }] 

Why is this? And how to modify the code to achieve what I want?

Upvotes: 0

Views: 50

Answers (3)

Rajesh
Rajesh

Reputation: 24915

This answer is an extension to @trincot's answer.

Using .filter + .map is not wrong, but it adds to extra iterations. Both these functions have their own specific use-case but when you need to do both, .reduce is more suited as you can manually parse object and return custom array/object.

Sample

context.createPanoramasPayload = panoramasFields.reduce(function(p, c) {
  if (c.type === 'file')
    p.push({
      name: 'index',
      value: uploadedPhoto
    });
  return p;
}, [])

Also note the use of anonymous function instead of arrow function(=>).

What arrow function does is it binds current context to the passed callback function, so that we can use this inside the callback. If you are using arrow function but not using this inside callback, you are wasting the efforts engine puts in binding context to the callback. For this reason, if you do not use this, in my understanding, its better to use anonymous function instead of arrow function.

Though its not wrong, but in my POV, it is a bad practice.

Upvotes: 0

trincot
trincot

Reputation: 350127

map returns an array that has the same length as the given array. It does not help to return just like that, as that will generate an undefined value in your mapped array. Instead you need to apply filter first:

context.createPanoramasPayload = panoramasFields.filter(field => {
    return field.type === 'file';
}).map(field => {
    return {
        name: 'index',
        value: uploadedPhoto
    }
})

This keeps with a functional way of programming.

As a side note, since the callback functions now don't do anything else than return something, you can use the expression syntax for the arrow functions:

context.createPanoramasPayload = panoramasFields
    .filter(field => field.type === 'file')
    .map(field => ({
        name: 'index',
        value: uploadedPhoto
    }));

Upvotes: 3

Mr.Pandya
Mr.Pandya

Reputation: 2038

You are using map function here, that means it will not reduce the length of the array. It return same length array. So use filter to get result.

Upvotes: 0

Related Questions