Selecting specific object inside array of objects throwing undefined in Vuejs /Java app - javascript

In this app im building i have a little problem referring to adress the SPA to the selected item by its id.
Fetching my data to my end point(action) i got a array of objects , then through a getter i just grab all that data, and using the function find() i filter all the array throwing the object which contains the id referrig to the selected one.Lets say:
First- Exposing on the router the link and the condition of the id which demark the object to select
{
path: '/game/selected/:gameCrabId',
name: 'GameSelectedView',
props:true,
component: GameSelectedView,
},
Second- Eexposing the component where in i access through router link the supposed object which contains the requested id
<v-btn router-link :to="`/game/selected/${game.game_id}`" >Access</v-btn>
Third-Initializing the view in general of the supposed selected object
<template>
<v-container v-if="allGames">
<!-- <div>{{gameSelected}}</div> -->
</v-container>
</template>
<script>
import { mapActions, mapGetters, mapState } from "vuex";
export default {
name: "GameSelectedview",
props: ["gameCrabId"],
data() {
return {};
},
// props:{SelectedGameComponent:Object},
methods: {
...mapActions(["allGames"])
},
computed: {
...mapGetters(["getSelectedGame"]),
gameSelected() {
return this.getSelectedGame(this.gameCrabId);
}
},
async created() {
await this.allGames;
await this.gameSelected;
await console.log(this.gameSelected);
},
</script>
then on my state managment component (Vuex) , i trigger the method getter which eventually brings me once i click that button of step 2 , the object which has the same id than the required one, but first im exposing the state where in that array of objects is
state: {
allGamesData: {all_games:[
{"game_id": 1,"game_player": "Romi","game_score": 0},
{"game_id": 2,"game_player": "Messi","game_score": 0},
{"game_id": 3,"game_player": "CR7","game_score": 0},
]
},
},
getters:{
getSelectedGame: (state) => (gameCrabId) => {
console.log(gameCrabId);
return state.allGamesData.all_games.find((gameID) => {
gameID.game_id === gameCrabId;
});
},
}
And this is the getter which eventuallly accesses the state and that array of objects , and using a double arrow function first aims to the state ,and second through the parameter (gameCrabId)which is the once that expose the id so neccesary to complete the link to that selected item;then returning the access to that array of objects in my state , i just use the function find() to establish a comparison between that id carried by the parameter (gameCrabId) and the array of objects brought from the state , breaking the cycle once find the first comparable item in the objects which match with that id gameID.game_id === gameCrabId
In order to see if ,my id carrier works i set a log , and works , the number is brought , but for any reason the filter find() throws me undefined in the object selected despite of already have the id once the comparison get settled, being imposible retrieve any information of that object

Missing return from find()
The callback to Array.prototype.find() must return a Boolean, but currently it returns nothing, so the result of find() would always be null:
return state.allGamesData.all_games.find((gameID) => {
gameID.game_id === gameCrabId; // FIXME: No return statement
});
Mismatched types
game_id is a Number, but gameCrabId is a string, and getSelectedGame() uses === to compare the two, which requires the operands to have the same type. One solution is to perform explicit type conversion to ensure both operands are Number:
getters: {
getSelectedGame: state => gameCrabId => {
return state.allGamesData.all_games.find((gameID) => {
// return gameID.game_id === gameCrabId; // DON'T DO THIS
return gameID.game_id === Number(gameCrabId);
});
}
}
demo

Related

React/Mobx mapping observable array to components

I'm stuck with trying to map an array to display components for each entry. Here's what I'm doing currently,
Here's my RankStore;
const RankStore = observable({
loading: false,
error: "",
rank: {} as RankInfo,
LoadRank() {
this.loading = true;
this.error = "";
GetRankInfo()
.then(action((json:any) => {
this.rank = json.rankDetails;
console.log(json)
this.loading = false;
}))
.catch(action((error: any) => {
this.error = error.message;
this.loading = false;
}));
}
});
export default RankStore;
In this observable RankStore I am loading the rank, which fetches from an API, and setting it to 'rank' which is an array of my model RankInfo, shown below;
interface RankInfo {
serviceNumber: string
capBadge: string
endDate: string
equivalentNatoRank: string
mainTrade: string
regtCorps: string
seniorityDate: string
actingPaidRank: string
startDate: string
substantiveRank: string
}
export default RankInfo;
Information received from the API looks like so;
Ordinary, to display this in a component, I would make the component an observer and simply call {RankStore.rank.serviceNumber} which works for my other Stores but not for this one as the data is a array containing two items. I am trying to MAP each array to a component so for each array it shows a component such as <h1> {RankStore.rank.serviceNumber} </h1> in this case it would render two components showing the respective service Numbers.
In the past I have done this as so;
{this.state.tickets.map((ticket) => (
<text key={ticket.id} value={ticket.id}>
{ticket.ticketApplication.firstName}{" "}
{ticket.ticketApplication.lastName}
</text>
))}
However, anytime I try to map {RankStore.rank} I always get 'MAP does not exist in 'rank''. What is the appropriate way to map arrays to components with MOBX?
It seems that you are setting the rank field as an object initially, and after the API call, changing it to an array. When rank is an object, it doesn't have the map function property on it.
So, instead of:
rank: {} as RankInfo
do this:
rank: [] as RankInfo[]
Initialize as an empty array of the RankInfo type.

How to find object in array by id number which is in another array in that object in vue

I have array of movie objects. I am passing id of movie genre to my state trying to extract object by movie genre ids. The problem is that every object in that array of movie objects have property named genre_ids which is an another array of multiple ids, and I am passing just one. I am having problem of mapping or find proper object that has that passed id in it's property genre_id which is array of multiple ids...can anyone help?
Here is the method in my state in which I am stuck
movieByGenre (state) {
return (genreId) => {
return state.popularMovies.find((movie) => {
movie.genreId.map((id) => {
return id === genreId
})
})
}
}
Here is data structure of movies
If I'm understanding your use case, something like this:
function movieByGenre(state) {
return genreId => {
const movies = state.popularMovies.filter(movie =>
movie.genre_ids.includes(genreId)
);
return movies[Math.floor(Math.random() * movies.length)];
};
}
This uses filter() to only return movies that the given genreId is in that movie's genre_ids collection. You can then use that filtered collection to return a single movie however you'd like.
after trying this solution I get error message in console "Error in render: "TypeError: Cannot read property 'title' of undefined""
NOTE: this is hardcoded genre id just for testing things out, which I know exist in movie collection
This is my component code from which I am calling state getter method
<template>
<p>{{movie.title}}</p>
</template>
<script>
export default {
genreId: "18",
computed: {
movie() {
return this.$store.getters.movieByGenre(this.genreId);
}
}
};
</script>

Delete a json inside another in React

Imagine that I have this kind of JSON object on my react state:
this.state={
parent:{
childs:[
child1:{
},
child2:{
},
child3:null,
(...)
]
}
}
to delete the child1 I did the following method:
deleteChild1 = (index,test) => {
const childs= [...this.state.parent.childs];
childs[index] = {
...childs[index],
child1: null
}
this.setState(prevState => ({
...prevState,
parent: {
...prevState.parent,
childs: [
...childs,
]
}
}))
}
This works with no problem, but imagine that I have 100 childs, I have to do 100 methods like this but instead putting the child1 to null I have to put the child100, child99, you get the idea.
My question is that is another way to put the variable null.
Thanks!
Currently your data structure isn't valid so its hard to write up a solution. If I try to create that exact state object it raises an exception Uncaught SyntaxError: Unexpected token : This is because you have an array written like an object. So first thing to do is adjust your state model to be valid syntax
this.state = {
parent: {
childs: {
child1: {
},
child2: {
},
child3: null,
...
}
}
}
Now, what you are describing / what you want to do is a dynamic key reference.
You can do this like so
const childTarget = 'child1'
childs = {
...childs,
[childTarget]: null
}
so to abstract that concept a little more. make it a function parameter
deleteChild = (childTarget) => {
then when you want to remove any particular child you can let them pass their value to this function
<Child onRemove={this.deleteChild} name={name} />
// name here would be like 'child1'
// assuming you are looping over state and rendering a child component for each item
and when the child calls this function
this.props.onRemove(this.props.name)
The answer is very simple, this would be my approach.
Create a function which updates your state with the expect result (removing that property).
If you wish to assign null that you can replace .filter() with a .map() solution. Typically if you are removing a piece of data it does not make sense to null it, but to remove it.
FYI your property childs is an array you have an object within, so you need a list of objects to fix this.
E.g.
[
{
name: "child1"
},
{
name: "child2"
},
{
name: "child3"
}
]
removeChild = (child) => {
const newChildList = this.state.parent.childs.filter(({name}) => name !== child);
this.setState(previousState => ({
...previousState,
parent: {
...previousState.parent,
childs: newChildList
}
}));
}
The key part here is that the data is being updated and overriding the original array. Because you have nested data structure we don’t want to delete any pre-existing data (hence the spreading).
Call the function however you want and if your childs array has an object with the property called name that matches the child function argument, it will be not be present on the next re-render.
Hope this helps.

Filtering away javascript objects into an array when using fetch

I have a react application, where I use the axios library, to get some values, and set them into an array of javascript objects in my state
componentDidMount(){
axios.get('http://localhost:8080/zoo/api/animals')
.then(res => this.setState({animals: res.data}))
}
Now I want to check if the objects, contains an Owner object, inside it, and filter out does that does,
First, I tried making a const, and then using the filter, to check if they contain the objects, and then set the state, but I can't save my values in a local variable
componentDidMount(){
const animals= [];
axios.get('http://localhost:8080/zoo/api/animals')
.then(res => animals=res.data)
console.log(animals) // logs empty array
console.log('mounted')
}
how can I make it so, that I can only get the animals that do NOT, have an owner object inside it?
Your animal array is empty in your second example because axios.get is asynchronous, what is in your then will be executed once the data is fetch, but the function will keep on going in the meantime.
To filter out your array, simply use filter right after fetching your data :
componentDidMount(){
axios.get('http://localhost:8080/zoo/api/animals')
.then(res => this.setState({animals: res.data.filter(animal => !animal.owner)}))
}
This function will filter out every animal object that does not have an owner property.
Working example :
const animals = [
{
name: 'Simba',
owner: {
some: 'stuff'
}
},
{
name: 1
}, ,
{
name: 2
}, ,
{
name: 3,
owner: {
some: 'stuff'
}
},
{
name: 'Bambi'
//status: 'dead'
}
]
console.log(animals.filter(animal => animal.owner))
EDIT: the answer was changed so that it only filters animals, that does not have an owner

How to update key value in immutable while filtering over List of Maps

I have an immutable List that looks like this:
this.state = {
suggestedUsers: fromJS([
{
user: {
client_user_id: "1234567890",
full_name: "marty mcfly",
image: "imageURL",
role_name: "Associate Graphic Designer",
selected: false
}
},
{
user: {
client_user_id: "0987654321",
full_name: "doc",
image: "imageURL",
role_name: "Software Engineer",
selected: false
}
}
)]
This is used in a div that displays this information in the UI.
When I click on the div, I have a function that is fired that looks like this:
selectUser(clientUserId){
// set assessments variable equal to the current team from the state
let assessments = fromJS(this.state.suggestedUsers)
let selectAssessor
// set a variable called selectedUsers equal to the results of filtering over the current suggestedUsers from the state
let selectedUsers = assessments.filter((obj) => {
// store immutable retrieval of the client user id in a variable called userId
let userId = obj.getIn(["user", "client_user_id"])
// when the user clicks 'Add' user, if the id of the user matches the selected user id
// the user, represented here by obj, is pushed into the selectedUsers array stored in the state.
if(userId === clientUserId){
return obj.setIn(["user", "selected"], true)
}
// If the user id is not equal to the selected user, that team member is kept in the
// current team array represented by the state.
return userId !== clientUserId
})
// update the state with the current representation of the state determined by the user
// selected team members for assessment requests
this.setState({
suggestedUsers: selectedUsers
})
}
The core of my question is this:
I would like to update the value of the 'selected' key in the users object to false, when this function is invoked.
I'm aware that I can't mutate the List I'm filtering over directly, but I've tried may different approaches to getting the selected value updated (i.e. using updateIn, and setIn). I know I need to set the result of calling setIn to a variable, and return that to the List I'm filtering over, but I can't get the value to update in the existing List. Any help is greatly appreciated. Thanks!
I've verified that this works the way it should when I change the value manually. How can I change it with immutable by updating this one List.
=========================================================================
Thank you to the community for your feedback. Filtering, and mapping did turn out to be overkill. Using immutability-helper, I am able to update the selected value of a particular user at the index that is clicked. One caveat that was not mentioned is using merge to bring your updated data into your previous data. After updating with immutability helper, I push the updated value into an array, then make it a List, and merge it into my original data. Code below:
let users = this.state.teamAssessments
let selectedArray = []
users.map((obj, index) => {
let objId = obj.getIn(["user", "client_user_id"])
if(objId === clientUserId){
const selectedUser = update(this.state.teamAssessments.toJS(), {
[index]: {
user : {
selected: {
$set: true
}
}
}
})
selectedArray.push(selectedUser)
}
})
let updatedArray = fromJS(selectedArray).get(0)
let mergedData = users.merge(updatedArray)
this.setState({
teamAssessments: mergedData
})
You need immutability-helper. Basically, instead of cloning the entire object you just modify small pieces of the object and re-set the state after you are finished.
import update from 'immutability-helper';
const newData = update(myData, {
x: {y: {z: {$set: 7}}},
a: {b: {$push: [9]}}
});
this.setState({varName: newData});
In other words, I would ditch the fromJS and the modifying of the array while enumerating it. First, enumerate the array and create your updates. Then, apply the updates separately. Also, to me the "selected" var seems redundant as you know if they are selected because the name of the array after filtration is "selectedUsers."
If I understand your question correctly, here's what I would suggest:
selectUser(clientUserId) {
let suggestedUsers = this.state.suggestedUsers.map(
userBlock =>
userBlock.setIn(
['user', 'selected'],
userBlock.getIn(['user', 'client_user_id']) === clientUserId
)
);
this.setState({
suggestedUsers,
});
}
To confirm -- you are just trying to modify state.suggestedUsers to have selected be true for the selected user, and false for everyone else? Sounds perfect for Immutable's map function (rather than filter, which will just return the elements of the list for which your predicate function returns something truthy).
BTW, you have an error in your object passed into fromJS -- you need an extra }, after the first assessor_assessment block.

Categories

Resources