0

I'm facing a problem with filter method. On my page there's an input to search matches by team names. Filter value is being stored to React state. Matches object looks like this:

[
    {
        "id": 4,
        "teamBlue": {
            "id": 36,
            "name": "nameForTeamBlue",
            "playerList": [
                {
                    [...]
                }
            ]
        },
        "teamRed": {
            "id": 37,
            "name": "nameForTeamRed",
            "playerList": [
                {
                    [...]
                }
            ]
        },
        "localDate": "2020-01-01",
        "localTime": "00:00:00",
        "referee": null,
        "commentator1": null,
        "commentator2": null,
        "streamer": null,
        "stage": {
            "id": 2,
            "name": "GROUPSTAGE"
        },
        "onLive": true,
        "finished": false
    },
]

I tried tons of methods to filter matches by team name, for example:

      let criteria = {
        teamBlue: {
          name: this.state.filter
        },
        teamRed: {
          name: this.state.filter
        }
      };
      let filteredMatches = this.state.matches.filter(function(item) {
        for (let key in criteria) {
          if (item[key] === undefined || item[key] !== criteria[key])
            return false;
        }
        return true;
      });
      console.log(filteredMatches);

but none of them worked. Is there any way to filter these matches so when I type "blue" into my input, it will show all matches where team name contains "blue"?

Thanks in advance!

1
  • You only filter by name or if criteria has key id then you want to filter by id as well? Commented Mar 22, 2020 at 11:36

3 Answers 3

1

Try updating the condition to:

if (!item[key] || item[key].name !== criteria[key].name)

let filteredMatches = this.state.matches.filter(function(item) {
    let flag = true;

    for (let key in criteria) {

      // update this to
      if (!item[key] || item[key].name !== criteria[key].name)
        flag = false;
    }
    return flag;
  });

Sign up to request clarification or add additional context in comments.

5 Comments

Ok, could you check you conditions inside if? and also update the json object and input (I don't see any blue in the json object)
let criteria = { teamBlue: { name: this.state.filter } }; also for teamBlue there is "name": "nameForTeamBlue" so it contains "blue"
@SajibKhan at the moment criteria[key] is { name: this.state.filter }, so you're comparing objects that always return false.
Try this condition: if (!item[key] || item[key].name !== criteria[key].name)
@Apraxia if name property was assumed all along then why even nest it in criteria, you could simplify with criteria = { teamBlue: this.state.filter...
0

The name property is missing :

if (key in item && item[key].name !== criteria[key].name)

Comments

0

You're comparing objects with === which will return false. You either need to use a deep comparison method from a library, or implement it yourself like below:

const matches = [ {"id": 4,
    "teamBlue": {
        "id": 36,
        "name": "nameForTeamBlue",
        "playerList": []
    },
    "teamRed": {
        "id": 37,
        "name": "nameForTeamRed",
        "playerList": []
    },
}, {"id": 4,
    "teamBlue": {
        "id": 36,
        "name": "nameForTeamBlue",
        "playerList": []
    },
    "teamRed": {
        "id": 37,
        "name": "nameForTeamRead",
        "playerList": []
    },
}]

const criteria = {
  teamBlue: {
    name: 'nameForTeamBlue',
  },
  teamRed: {
    name: 'nameForTeamRed',
  }
}

const filteredMatches = matches.filter((item) => {
  const allCriteriaMatched = Object.entries(criteria)
    .every(([key, value]) => {
      const matched = Object.entries(value).every(([criteriaKey, criteriaValue]) => {
        const itemValue = item[key][criteriaKey]
        const matched = itemValue == criteriaValue
        if (!matched) console.log('Item %s does not matched criteria %s. Item\'s value is %s, but criteria value is %s', item[key]['id'], criteriaKey, itemValue, criteriaValue, criteriaValue)
        return matched
      })
      if (!matched) return false
      return true
    }, {})
  return allCriteriaMatched
})
console.log(filteredMatches);

Basically, you just need to go 1 level deeper :D if your criteria can have multiple nested objects, then there's no point doing it manually. You can try to map criteria to run against matches so that you don't use === on objects, but only primitives.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.