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.
Related
I'm trying to make a filter based on a Strapi relation.
My Strapi response looks like this:
I'm using Next Js for the frontend, so I assign props like so:
return {
props: {
projects: data.projects.data,
categories: categoriesData.data.categories.data,
},
}
I map through all of the project and list them all as cards. Then I want to filter them based on a button click. The buttons are the categories names and I map over that array as well. On click of each button I run a function called "handleProjects" and this is where I run into an issue.
I have previously made a filter using SanityCMS and Next Js, however, the code structure of the response in Sanity is much clearer compared to that of Strapi.
This is the code I've used in my previous project with Sanity:
const [filteredProducts, setFilteredProducts] = useState(products)
function handleProducts(e) {
let categoryType = e.target.value
setFilteredProducts(
products.filter((product) => product.category == categoryType)
)
}
I'm using this query where I alias the category as such and it is much simpler:
const productQuery = `*[_type == "product"] {
_id,
slug,
name,
image,
"category": category->name
}`
My function for my Strapi project looks like this:
function handleProjects(e) {
let categoryType = e.target.value
setFilteredProjects(
projects.filter((project) =>
project.attributes.categories.data.map((i) =>
i.attributes.title.includes(categoryType)
)
)
)
}
I'm having an array of objects, but at some point I have to map over an array of objects one level deeper and see if the categoryType matches some of the object values two levels deep.
Can anyone show me what I'm doing wrong here?
My problem is that item stored in object (in an array of objects inside a state hook) is not being rendered on page, but it gets printed with console.log
I fetched some data from the server and it worked as expected, returning an array of two items, one of which is an object containing blog data(blog heading, creator, etc) an another is an array of 'sections' of that blog. Here is how I did it,
This is the initialization
// Get the blog id
const {blog_id} = useParams();
// Declaring our state hooks
const initial_blog_state = {
blog_id: blog_id,
heading: '',
creator: {},
created: '',
section: [],
}
const [blog_state, updateBlogState] = useState(initial_blog_state);
Here is the fetching of data from the server
useEffect(() => {
// Fetching data
Promise.all([
fetch(`http://127.0.0.1:8000/api/blog/${blog_id}`),
fetch(`http://127.0.0.1:8000/api/section/full/${blog_id}`)
]).then(responses => {
// Get a JSON object from each of the responses
return Promise.all(responses.map(response => {
return response.json()
}))
}).then(function (data) {
// Log the data to the console
console.log(data);
// Update state
updateBlogState({
...blog_state,
heading: data[0].heading,
creator: data[0].creator,
created: data[0].created,
section: data[1]
})
}).catch(function (error) {
// if there's an error, log it
console.log(error);
});
}, []);
I think the way I'm updating the section inside the hook can be a problem(although I'm not sure how), because I saw in a stackoverflow answer that objects must always be initialized (which I'm not doing when declaring an array of 'objects')
And here is the thing that needs to be rendered
return (
<div className="container">
<h1>{blog_state.heading}</h1>
<p className="text-small text-muted">{blog_state.creator.username}</p>
{blog_state.section.map(item => {
{console.log(item.paragraph)}
<p>{item.paragraph}</p>
})}
</div>
)
Here blog_state.heaing and blog_state.creator.username are being rendered as desired and also console.log(item.paragraph) prints the correct paragraph on the console window, but item.paragraph doesn't show anything on the page.
Nothing is being returned from your map.
i.e you need to add a return line before the <p>{item.paragraph}</p>
So:
{blog_state.section.map(item => {
console.log(item.paragraph)
return <p>{item.paragraph}</p>
})}
or as an inline return:
{blog_state.section.map(item => <p>{item.paragraph}</p>)}
In my React application, I have a filter component. Everytime I apply filters, I am calling an api by passing the selected filter values from Front End. Filter component has checkboxes so when I am selecting multiple values, it is being passed as an array of strings currently. I want to send the selected filter values as string instead of Array of Strings. I have total 2 filters- Date, Name. In my Parent component, the filters param in handleFilterChange will have all two values i.e Name as Array of Strings and Date as String which I am sending in request payload as part of filterCondition object. I want to change Name alone to String.
ParentComponent.js-
const ParentComponent = props => {
const [filterObj, setFilterObj] = useState({});
const handleFilterChange = filters => {
console.log(filters); // Show the filter values-Date(String), Name(Array of Strings)
const reqParams ={
id,
filterCondition: filters // An object with Name(Array) and date(string)
}
setFilterObj(filterObj);
//API call which will pass filters in request params
fetchApi(reqParams);
};
return (
<ChildComponent onChange={handleFilterChange} />
);
}
fetchApi will always send name and Date in filterCondition object. My code is working fine, the only change I want to do now is to change Array to String for name.Currently, with the above code my request structure looks like this-
Current Request Structure-
{
id:1,
filterCondition: {
name: ['XYZ', 'ABC'],
date: '2020-06-29T00:00:00'
}
}
I want my request to be like below-
Expected request structure-
{
id:1,
filterCondition: {
name: 'XYZ, ABC',
date: '2020-06-29T00:00:00'
}
}
Can someone help me understand how can I achieve the above expected request structure.
To convert Array to String you can use join(separator) function
var obj = {
id:1,
filterCondition: {
name: ['XYZ', 'ABC'].join(','),
date: '2020-06-29T00:00:00'
}
}
console.log(obj);
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
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>