Shashika Virajh
Shashika Virajh

Reputation: 9487

JS filter doesn't work properly when filtering an array

In my react native application, I have the following array.

export const ID_OPTIONS = [
  { id: 'nric_fin', name: 'NRIC/FIN' },
  { id: 'passport', name: 'Passport' },
  { id: 'birth_cert', name: 'Birth Certificate' },
];

I tried to filter this array as follows.

setSelectedIdType = (idType) => {
  return ID_OPTIONS.filter((type) => {
    if (type.id === idType) {
      return type.name;
    }
    return null;
  });
}

But, this return an object. I want to get the name as the result. What am I doing wrong here?

Upvotes: 1

Views: 6323

Answers (6)

Theo Markovic
Theo Markovic

Reputation: 11

Is it necessary for your domain to store the objects in a array?

Since you've declared them as constants I'm going to make the assumption that they won't change unless the client is reloaded.

If you were to transform this array of objects into a simple object like so:

const NAMES = ID_OPTIONS.reduce((obj,idOption) => {
  obj[idOption.id] = {name: idOption.name};
  return obj;
},{});

which will result in:

{
  nric_fin: {name: 'NRIC/FIN'},
  passport: {name: 'Passport'},
  birth_cert: { name: 'Birth Certificate'}
}

and now you access the name by property

let idType = 'passport';
NAMES[idType];

Upvotes: 0

Akrion
Akrion

Reputation: 18525

Instead of Array.filter just use Array.find since filter returns the filtered array instead of one item. Array.find returns the first matched item on which you can then take the name:

As per Array.filter docs - return value:

A new array with the elements that pass the test. If no elements pass the test, an empty array will be returned.

And in regards to the test function which Array.filter executes per each iteration:

Function is a predicate, to test each element of the array. Return true to keep the element, false otherwise.

Note that the return value is boolean.

With Array.find your function could just be:

const ID_OPTIONS = [ { id: 'nric_fin', name: 'NRIC/FIN' }, { id: 'passport', name: 'Passport' }, { id: 'birth_cert', name: 'Birth Certificate' }, ];

let setSelectedIdType = idType => 
  (ID_OPTIONS.find(x => x.id === idType) || {}).name

console.log(setSelectedIdType('nric_fin'))
console.log(setSelectedIdType('passport'))

Upvotes: 3

Ry-
Ry-

Reputation: 225281

It looks more like you’re looking for a for loop:

setSelectedIdType = (idType) => {
  for (let type of ID_OPTIONS) {
    if (type.id === idType) {
      return type.name;
    }
  }
  return null;
}

The equivalent can be implemented using find:

setSelectedIdType = (idType) => {
  let type = ID_OPTIONS.find(type => type.id === idType);
  return type && type.name;
}

(This returns undefined instead of null when the id isn’t found; something like type === undefined ? null : type.name will change that if necessary.)

Upvotes: 4

6502
6502

Reputation: 114599

A filter filters elements out of an array... it doesn't matter what you are returning exactly, the return value will be treated simply as either "truthy" or "falsy" (elements for which the function returns a "truthy" value are kept, others are discarded).

All non-empty strings are "truthy" in Javascript.

Upvotes: 3

Jack Bashford
Jack Bashford

Reputation: 44145

Just map the array afterwards to get the name.

return ID_OPTIONS.filter(...).map(({ name }) => name);

You could alternatively use reduce to reduce complexity:

setSelectedIdType = idType => ID_OPTIONS.reduce((a, { id, name }) => id == idType ? (a.push(name), a) : a, []);

Upvotes: 2

Sen
Sen

Reputation: 338

Quoting from Mozilla Filter Function Docs

callback Function is a predicate, to test each element of the array. Return true to keep the element, false otherwise.

Return value A new array with the elements that pass the test. If no elements pass the test, an empty array will be returned.

I dont think callback for filter can be other than boolean while the return value should be an array containing the matched result from the filter function

Upvotes: 0

Related Questions