Search code examples
reactjsreduxreselect

how to filter through an array and check if a nested object includes a value of true using reselect in redux


I'm new to reselect and I've been having success with creating selectors so far until I tried to filter a list by a nested key value pair. Most of the options are strings or array of strings and they are working just fine, but I can't figure out how to filters this list by the true/false values in an object.

here is my working selector so far and the json I'm using it to sort

const getItemsVisibilityFilter = state => state.itemsVisibilityFilter
const getItems = state => state.items

export const getVisibleItems = createSelector(
  [getItemsVisibilityFilter, getItems],
  (itemsVisibilityFilter, items) => {
    switch (itemsVisibilityFilter) {
      case 'SHOW_ALL':
        console.log(items)
        return items
      case 'SHOW_DAMAGE':
        return items.filter(item => item.tags.includes('Damage'))
      case 'SHOW_ATTACK_SPEED':
        return items.filter(item => item.tags.includes('AttackSpeed'))
      case 'SHOW_LIFE_STEAL':
        return items.filter(item => item.tags.includes('LifeSteal'))
      default:
        return items
    }
  }
)

and this is a single item from the JSON

   "1036": {
        "stats": {
            "FlatPhysicalDamageMod": 10
        },
        "description": "<stats>+10 Attack Damage</stats>",
        "gold": {
            "total": 350,
            "sell": 245,
            "base": 350,
            "purchasable": true
        },
        "tags": [
            "Damage",
            "Lane"
        ],
        "plaintext": "Slightly increases Attack Damage",
        "image": {
            "full": "1036.png",
            "group": "item",
            "sprite": "item0.png",
            "h": 48,
            "w": 48,
            "y": 48,
            "x": 48
        },
        "sanitizedDescription": "+10 Attack Damage",
        "maps": {
            "8": true,
            "10": true,
            "11": true,
            "12": true,
            "14": false,
            "16": false,
            "18": true,
            "19": true
        },
        "into": [
            "3077",
            "3123",
            "1053",
            "3155",
            "3134",
            "3133",
            "3034",
            "3035",
            "3044",
            "3052",
            "3072",
            "3122",
            "3144",
            "3252"
        ],
        "id": 1036,
        "name": "Long Sword"
    },

my question is how do I filter through the "maps" object and return the items that have a value of true? If this helps. what I would like to add to the original selector is 'SHOW_SUMMONERS_RIFT' - "maps": {11: true} like so

const getItemsVisibilityFilter = state => state.itemsVisibilityFilter
const getItems = state => state.items

export const getVisibleItems = createSelector(
  [getItemsVisibilityFilter, getItems],
  (itemsVisibilityFilter, items) => {
    switch (itemsVisibilityFilter) {
      case 'SHOW_ALL':
        console.log(items)
        return items
      case 'SHOW_DAMAGE':
        return items.filter(item => item.tags.includes('Damage'))
      case 'SHOW_ATTACK_SPEED':
        return items.filter(item => item.tags.includes('AttackSpeed'))
      case 'SHOW_LIFE_STEAL':
        return items.filter(item => item.tags.includes('LifeSteal'))
      case 'SHOW_SUMMONERS_RIFT':
        return items.filter(item => item.maps.includes(I don't know what or to put here to see if 11 === true))
      default:
        return items
    }
  }
)

If this isn't enough code to help provide a solution. please let me know and I can post anything you think would be more relevant. Or if there are docs somewhere I should be reading more... Everything I have found though is about updating nested objects and I can't find anything about comparing values. please and thank you

SOLUTION --- thanks to Hardik Modha for putting me on the right path. I don't know if this is the best solution or even a good way for using Reselect, Redux, or even plain javascript haha, but here is the case I came up with and it works for the selector based on a nested object

  case 'SHOW_SUMMONERS_RIFT':
    const riftItems = items.filter(item => {
      const mapKey = Object.keys(item.maps)
      const mapValue = Object.values(item.maps)
      if (mapKey[2] && mapValue[2] === true) {
        return item
      }
      return null
    })
    return riftItems

Solution

  • You just need to get all entries first using Object.keys and then filter the entries which are having value true using filter

    const filtered = Object.keys(map.maps).filter((item) => map.maps[item]);

    const myObject = {
       "1036": {
            "maps": {
                "8": true,
                "10": true,
                "11": true,
                "12": true,
                "14": false,
                "16": false,
                "18": true,
                "19": true
            },
        },
       "1037": {
            "maps": {
                "8": false,
                "10": true,
                "11": true,
                "12": false,
                "14": false,
                "16": false,
                "18": true,
                "19": true
            },
        },
       "1038": {
            "maps": {
                "8": true,
                "10": false,
                "11": true,
                "12": true,
                "14": false,
                "16": false,
                "18": false,
                "19": true
            },
        },
    }
    
    Object.keys(myObject).forEach((key) => {
      const maps = myObject[key].maps;
      console.log(Object.keys(maps).filter(item => maps[item]));
    });