1

I am working on a React JS application, which is a match score predicting app.

With the following code the app currently displays a list of upcoming matches for which the user can click on and enter a prediction.

if(!this.props.loading && !this.props.error){
upcomingmatches = this.props.upcmgMatches.map(upcomingMatch => {
    return <UpcomingMatch
        key={upcomingMatch.id}
        teamA={upcomingMatch.teamA}
        teamB={upcomingMatch.teamB}
        matchKickoff={upcomingMatch.matchKickoff}
        clicked={() => this.addInitInputMatchResultHandler(upcomingMatch.id, upcomingMatch.teamA, upcomingMatch.teamB, upcomingMatch.matchKickoff)}
    />
});
}

I want to modify it so that if a user has already made a prediction for a match then it will display the component but with additional info e.g. their current predictions.

My component has access to two object arrays which are received from a Firebase table and turned into arrays.

upcmgMatches shows all the current upcoming matches that a user can make a prediction for.

userPredictions shows all the matches that the user had made predictions for that have still not been played. So this could include all matches in upcmgMatches if they've made predictions for all of them or just a subset of these matches or I guess an empty array if they haven't made any predictions.

These arrays are shown below.

So id from upcmgMatches should be matched with matchID in userPredictions

upcmgMatches = [{
    "matchKickoff": "2018-09-22T10:45",
    "teamA":"Roosters",
    "teamB":"Dragons",
    "id":"-LN-pNFv-rFJQkunM1Tv"
  },  
  {
    "matchKickoff": "2018-09-22T19:00",
    "teamA": "Storm",
    "teamB": "Sharks",
    "id": "-LMrXWzcEjN_u_jlULuJ"
  }]

userPredictions = [{
    "matchID": "-LMrXWzcEjN_u_jlULuJ",
    "teamAName": "Storm",
    "teamAScore": "22",
    "teamBName": "Sharks",
    "teamBScore": "12",
    "userId": "J2QO4OHT5vc7aAkT9vcdREo1IuW2",
    "id": "-LMvzSoaMAhBUhgWMOpM"
  }]

So I think my modified logic would be ..

For each match in upcmgMatches, check whether the id exists in userPredictions on the matchID field, if it does then return the UpcomingMatch component with the additional info from userPredictions namely TeamAScore and teamBScore. If it doesn't then just return the info from upcmgMatches, which should be the same but without predicted scores.

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
chucknor
  • 837
  • 2
  • 18
  • 33
  • Those are not arrays; those are objects with properties. Could you please show what the arrays look like? There are a number of questions which detail how to check if an array contains an element of another (e.g., [Check if an array contains any element of another array in JavaScript](https://stackoverflow.com/q/16312528) or simply using the answers from [How do I check if an array includes an object in JavaScript?](https://stackoverflow.com/q/237104) in a loop. – Heretic Monkey Sep 25 '18 at 15:25
  • Hi. Sorry I know that what I pasted above are objects not arrays. I just wanted to show what the objects contained. Should have been more explicit. These do come to this component as arrays of objects. The Chrome console shows ...upcoming matches : [object Object],[object Object],[object Object],[object Object] and Predictions : [object Object],[object Object]. The map function above does work when Im just working with the upcomingMatches and not predictions so this would indicate they are coming though as an array of objects right? – chucknor Sep 25 '18 at 18:29
  • Please [edit] your question to include example data as it is received by your function; the easiest way to do this is `console.log(JSON.stringify(this.props.upcmgMatches))`. Then we can reproduce your issue and better help to understand what's going on. See [mcve] for help in constructing it. – Heretic Monkey Sep 26 '18 at 13:19
  • Ok. I have done that HM. Thanks. – chucknor Sep 26 '18 at 16:11

1 Answers1

0

You can get the outer object key with Object.keys()

const getFirstKey = o => Object.keys(o)[0]

const getMatchIds = matches => matches.map(getFirstKey)

Then you can check the list of userPredictions against it.

const isUserMatch = matchKey =>
  getMatchIds(userPredictions)
    .includes(matchKey)

const upcomingUserMatches = upcomingMatches
  .map(getFirstKey)
  .filter(isUserMatch)
Benny Powers
  • 5,398
  • 4
  • 32
  • 55
  • Sorry Benny. I'm not sure how to implement the solution you have proposed. I didn't make it clear in my original description but both matches and predictions are available to the component as arrays of objects i.e. [object Object],[object Object] (above is just the object representation). – chucknor Sep 26 '18 at 10:34
  • these are firebase records, right? which have a generated firebase key as the root of the object. So to get the object id, you need to get the list of keys first. That's why we map get first key over upcomingMatches, to get the list of upcoming match ids. Then we can compare that list to a similar list of user predictions. – Benny Powers Sep 26 '18 at 11:15
  • Yes these are Firebase records, but I convert them to arrays in my reducer with .. for ( let key in res.data ) { fetchedUpcomingMatches.push( { ...res.data[key], id: key } ); So they are available to my component as an array of objects. – chucknor Sep 26 '18 at 13:23
  • right, so Object.keys is a functional way to derive an array of keys from an object. Since it doesn't require a loop, it's more readable. you can read the final line of my proposed solution almost as english: "get the list of first keys of each upcoming match, then filter that list for only the user predicted matches" – Benny Powers Sep 26 '18 at 13:25