dardub
dardub

Reputation: 3195

Conditional Javascript Filter

I have a object containing the following:

assets = [
  { id: 1, type: 'image', url: 'image.jpg' },
  { id: 2, type: 'video', url: 'video.mp4' },
]

I'd like to filter based on user selection of IMAGE, VIDEO, or ALL.

I cannot think of a clean way to filter use for the ALL case.

currentOption = 'image'
assets.filter(asset => asset.type === currentOption)

This will work for IMAGE or VIDEO, but not ALL.

I could check in my filter function:

const currentOption = 'all'
const filterFunc = asset => {
  if (currentOption == 'all') return true
  return asset.type === currentOption
}
assets.filter(filterFunc)

But wouldn't it be better to short-circuit the filter to not iterate each item?

Edit: To answer questions why not skip filter all together. I was trying to keep it framework agnostic. But this is rendered using react. So I would have to do something like:

<div>
{currentOption === 'all' ?
  assets.map(asset => 
   <img src={asset.url} />
  )
  :
  assets.filter(asset => asset.type === currentOption).map(asset =>
   <img src={asset.url} />
  )
}
</div>

Plus this doesn't even account for the code to display a video. Basically I was trying to reduce duplication in the view code.

Upvotes: 16

Views: 42746

Answers (4)

Th&#233;o T. Carranza
Th&#233;o T. Carranza

Reputation: 8459

This might work for you:

assets.map(
    filter(
        asset {
            return !currentOption ? asset : asset.type === currentOption
    }
)

You could go a step further and declare an 'all' current option if you think that would be more explicit.

Hope it helps!

Upvotes: 0

trincot
trincot

Reputation: 351369

You could use the ternary operator to decide whether or not to apply the filter:

currentOption === 'all' ? assets : assets.filter(asset => asset.type === currentOption)

The mapping to images, that you added to the end of your question, could be written like this:

(currentOption === 'all' ? assets : assets.filter(asset => asset.type === currentOption))
    .map( asset => <img src={asset.url} /> )

Upvotes: 14

alonkol
alonkol

Reputation: 390

I would go with what you suggested, more or less:

assets.filter(asset => currentOption === "all" || asset.type === currentOption);

Keep in mind that filter() iterates over all of the items anyway.

Upvotes: 6

Christian Benseler
Christian Benseler

Reputation: 8075

You can do something like this:

let currentOption = null; //or 'image', or 'video'
const new_assets = 
  assets.filter(asset => !currentOption || asset.type === currentOption)

set currentOption to null if you don't want to filter, or if set it to anything, consider to do the comparison. But as said before, filter() will iterate over the entire array. It will be more wise to check the currentOption before, if it is 'all' you can just copy the array.

Upvotes: -3

Related Questions