Fetched object returns underfined - javascript

I have my data objects that I need to fetch, looking like this:
const products = {
one: {
id: 1,
name: 'One',
image: oneImage,
chair: {
name: 'ChairName',
image: myImage,
colors: {
white: {
name: 'White',
image: myImage,
},
black: {
name: 'Black',
image: myImage,
},
},
},
},
},
two: {
id: 2,
name: 'Two',
image: twoImage,
chair: {
name: 'Chair,
image: myImage,
colors: {
white: {
name: 'White',
image: myImage,
},
black: {
name: 'Black',
image: myImage,
},
},
},
},
};
I am fetching them with Object.value
const ProductsData = Object.values(products).map((data) => {
return (
<>
<div className="box" onClick={() => setSelectedData(data)}>
<img src={data.image} />
</div>
);
});
This code above works just fine, pointing out to selected data like this:
{selectedData ? (
<h1>{selectedData.name}</h1>
) : null}
But now I would like to map through the chair colors of selected Data, which causes errors.
What I tried to do was to just {selectedData.chair.colors.name}, which prints nothing and by console.log is underfined
How can I print selectedData of chair colors and how I can set the picked color as new selectedData? I am getting lost.

If you want to choose color, then you need to store it in another state variable.
const [selectedColor, setSelectedColor] = React.useState();
Use Object.values to iterate chair.colors
{Object.values(selectedData.chair.colors).map(val => {
return <div onClick={() => setSelectedColor(val.name)}>{val.name}</div>
})
}
Check this sandbox

You don't have selectedData.chair.colors.name, look again in your structure. There is selectedData.chair.colors.white.name or selectedData.chair.colors.black.name

colors is an object again. It does not have a property name. It has properties like white and black which are objects themselves.
Map through:
Object.values(selectedData.chair.colors)
let selectedChairColors = Object.values(selectedData.chair.colors)
;
console.log(selectedChairColors[0])
console.log(selectedChairColors[1])
You can log selectedChairColors to see that this will give you an array of values of colors property in chair of selectedData.
Looking at your sandbox it seems you are using no checks while running selectedData and hence the error. (Initially, selectedData is undefined).
This should work:
<div>{selectedData && Object.values(selectedData.chair.colors).map((x)=>
JSON.stringify(x)
)}</div>
Here is sandbox forked out of yours.

Related

how can i add object in array which is in object as property (react.js )

first off, sorry for the confusing title. I couldn't find a way to say this more clearly.
These days, I'm working on my own project and face a problem. If you can give me some
advice, it would be a huge help for me.
So, this is my State
const[state, setState] = useState({
externalEvents: [
{ title: "Art 1", color: "#0097a7", id: 34432, custom: "fdsfdsfds" },
{ title: "Art 2", color: "#f44336", id: 323232 },
{ title: "Art 3", color: "#f57f17", id: 1111 },
{ title: "Art 4", color: "#90a4ae", id: 432432 },
]
});
and this is my input tags and function
<form className="todoinput" onSubmit={addTodo} >
<input type="text" value={title} onChange={e=>setTitle(e.target.value)} placeholder="Add event" />
<input type="text" value={custom} onChange={e=>setCustom(e.target.value)} placeholder="detail" />
<select>
<option value={()=>{setColor('blue')}}>blue</option>
<option value={()=>{setColor('orange')}}>orange</option>
<option value={()=>{setColor('green')}}>green</option>
<option value={()=>{setColor('purple')}}>purple</option>
</select>
<button type="submit">Add todo</button>
</form>
const addTodo = (e) =>{
e.preventDefault();
setState([...state.externalEvents,{title:{title}, color: {color}, custom: {custom}}])
setTitle('')
setCustom('')
}
This is what I wanted to make: I type title,custom and select color in input and select tags. And I submit it, then function is going to add new object in externalEvents(array)
I used spread to do this, but somehow it didn't work and console says "TypeError: Cannot read property 'map' of undefined"
<div id="external-events">
{state.externalEvents.map((event) => (
<div
className="fc-event"
title={event.title}
data-id={event.id}
data-color={event.color}
data-custom={event.custom}
key={event.id}
style={{
backgroundColor: event.color,
borderColor: event.color,
cursor: "pointer"
}}
>{event.title}</div>
))}
</div>
this is a part where map() happen, I think the reason map couldn't read property is because
I failed to send proper property to externalEvents.
thanks for reading, and your help will be appreciated.
p.s I used FullCalendar library!
When you initialized your state, it was an object with a key externalEvents which is an array
useState({
externalEvents: [
{ title: "Art 1", color: "#0097a7", id: 34432, custom: "fdsfdsfds" },
{ title: "Art 2", color: "#f44336", id: 323232 },
{ title: "Art 3", color: "#f57f17", id: 1111 },
{ title: "Art 4", color: "#90a4ae", id: 432432 },
]
})
But when you update your state, it is an array
setState([...state.externalEvents,{title:{title}, color: {color}, custom: {custom}}])
So based on your initial state, setState should be as below
setState({
...state,
externalEvents: [
...state.externalEvents,
{title, color, custom}
]})
Do note that {title, color, custom} is probably what you want, instead of {title: {title}, xxxx
Your problem is probably inside of your addTodo function.
This function sets state to be an array. Following this, state.externalEvents no longer exists.
To test this, try console.log(state) after it has been set in addTodo function.
Based on your intent, here is a modification of your addTodo function that may solve your problem:
const addTodo = (e) =>{
e.preventDefault();
// Use previous state, and make sure to return an object with an 'externalEvents' key as the new state
setState((prevState) => {
const newEvent = {} // whatever your new event is
return { externalEvents: [...prevState.externalEvents, newEvent] }
})
setTitle('')
setCustom('')
}
Further improvement
Furthermore, you can make things more simple by directly having an externalEvents piece of state, to remove the need for a nested externalEvents property inside some other state object.
For example:
const [externalEvents, setExternalEvents] = useState([
{ title: "Art 1", color: "#0097a7", id: 34432, custom: "fdsfdsfds" },
{ title: "Art 2", color: "#f44336", id: 323232 },
{ title: "Art 3", color: "#f57f17", id: 1111 },
{ title: "Art 4", color: "#90a4ae", id: 432432 }
])
If you adopt this, you would need to update your addTodo function once again, specifically the state update step.
Your state update step will now look like this:
setExternalEvents((prevExternalEvents) => {
const newEvent = {} // whatever your new event is
return [...prevExternalEvents, newEvent]
})
See here for more:
Setting state based on the previous state: useState hook, setState function. Accessing previous state value
I think that the issue is that you defined state as an object, with the key externalEvents, which is an array. But when you are submitting the form, in the setState function, you are setting an array, not the original shape.
I recommend you to do it like this:
const [externalEvents, setExternalEvents] = useState([
{ title: "Art 1", color: "#0097a7", id: 34432, custom: "foo" },
{ title: "Art 2", color: "#f44336", id: 323232 },
{ title: "Art 3", color: "#f57f17", id: 1111 },
{ title: "Art 4", color: "#90a4ae", id: 432432 },
]);
And in the form:
const addTodo = (e) => {
...
setExternalEvents(prev => [...prev, {title, color, custom}])
...
}

Set nested property of json object using brackets notation in PUT request (svelte + strapi)

I'm using Svelte and Strapi for the project.
Here is a simplified version of my problem:
The json where I want to send my PUT request. (localhost:1337/shapes/1)
{
id: 1,
name: 'square',
colors: {
red: false,
blue: false,
green: false
}
}
The toggle buttons in svelte template:
{#each shapes as shape}
<div on:click={toggleColor(shape, "red")}>red</div>
<div on:click={toggleColor(shape, "blue")}>blue</div>
<div on:click={toggleColor(shape, "green")}>green</div>
{/each}
The toggle function (see comments to find what's missing):
function toggleColor(shape, color) {
let index = shapes.indexOf(shape);
axios.put(`http://localhost:1337/shapes/${shape.id}`, {
// How to write this part to toggle a color?
// The commented code below doesn't work as it doesn't set a color without
// reseting others siblings
// colors: {
// [color]: shape.colors[color] ? false : true
// }
})
.then((res) => {
coins[index].colors[color] = res.data.colors[color];
})
.catch((err) => {
console.log(err.message)
});
}
To understand more clearly what happens with this version, it returns this response if I click on blue button then red button:
{
id: 1,
name: 'square',
colors: {
red: true,
blue: null,
green: null
}
}
Expected response:
{
id: 1,
name: 'square',
colors: {
red: true,
blue: true,
green: false
}
}
You was almost there. The following code:
{
colors: {
[color]: shape.colors[color] ? false : true
}
}
...will redefine colors as an object with only a single color in it. To also get the previous colors, use the spread syntax like:
{
colors: {
...shape.colors,
[color]: shape.colors[color] ? false : true
}
}

Strange behaviour of Object.keys(Obj[0]).map() :[] function

I have this code in running, here I have given hard coded [0] value,
using this data in <MaterialTable columns={Here using data for table} />,
it should render only first row, but instead its rendering all rows after giving hardcoded 0,
How this result into rendering all columns with all rows and iterating two time?
previewData = [
{id: 1, name: "FileName", size: 15690, type: "doc", Date: "DDMMYY"}
{id: 2, name: "FileName", size: 15690, type: "doc", Date: "DDMMYY"},
{id: 3, name: "FileName", size: 15690, type: "doc", Date: "DDMMYY"},
{id: 4, name: "FileName", size: 15690, type: "doc", Date: "DDMMYY"}
]
Object.keys(props.previewData[0]).map((x) => {
if(x=="id"){return <div>{x}</div>}
) : []
Strange working code:
const columns = () => {
return (
props.previewData && props.previewData.length > 0 ?
Object.keys(props.previewData[0]).map((x) => {
if (props.Table && props.Table !== "nameTable") {
if (x === "id"){
return ({
title: ,
field: x,
width: "500rem",
sorting: false
})// similar code for other fields also
// this code should gets called only once for array [0], its get iterated over from `.forEach()` from data of MaterialTable How???
}
return (
<MaterialTable
title = ""
icons={}
options={{
}}
columns={columns()}
data={
props.previewData && props.previewData.length > 0 ? props.previewData.map((row) => {
const eachRowData = {};
Object.keys(row).forEach((y) =>{
})
return eachRowData;
}) : []
}
/>
Object.keys(props.previewData[0]) with your example previewData is:
["id", "name", "size", "type", "Date"]
Then you map those values to:
[<div>id</div>, undefined, undefined, undefined, undefined]
because you've used map (not filter) and returned something only when the x parameter's value is "id", which is only true for one of the five elements in the array.
It's not clear to me from your question what you want to do instead, but that's why you're getting an array with five elements rather than one. It almost seems like you're trying to filter so you only produce one div, but you're filtering based on a hardcoded value ("id") which would mean you wouldn't need map at all, you'd just do:
<div>{props.previewData[0].id}</div>

How to pass a sectionlist sectionHeader's index to the reducer?

Looking to map items with index using SectionList, I was successfully able to map the index of the sections and pass the state to the reducer, however, the section header has a different index and would like to do the same with it. Help me up with some examples if possible. This is something that I am developing for a food tech app which and I want to implement the Cart Functionality in the App.
SectionList:
<SectionList
sections={this.props.user.dailyMenuData.item.map(
({category, data}, index2) => ({category, data, index2}),
)}
keyExtractor={this.keyExtractor}
renderItem={this.renderMenu}
renderSectionHeader={({section: {category, index2}}) => (
<CText style={styles.headerStyle}>{category}</CText>
)}
/>
The above data is coming from MongoDB like below:
DATA = {
vendor_id: XXXXXX (For Mapping Vendor to the Menu)
company_id: XXXXX (For Mapping the Customer to the Menu)
item: [
{
category: 'A La Carte',
data: [
{
src:
'https://cdn.pixabay.com/photo/2017/08/01/14/22/fruits-2565817_960_720.jpg',
name: 'Coffee with Pancakes',
price: '160',
rating: 3.8,
calorie: '130',
},
}],
},
The AddtoCart Reducer is dynamically getting the value of the index of data[] however it is not able to get the index of item[] from the API called. The reducer code is given below:
case ADDTOCART:
return update(state, {
dailyMenuData: {
item: {
1: {
data: {
[payload.index]: {
quantity: {
$set:
state.dailyMenuData.item[1].data[payload.index].quantity +
1,
},
},
},
},
},
},
})

Make a Tree view from JSON data using React JS

First of all i am very new to React JS. So that i am writing this question. I am trying this for three days.
What I have to do, make a list of category, like-
Category1
->Sub-Category1
->Sub-Category2
Categroy2
Category3
.
.
.
CategoryN
And I have this json data to make the listing
[
{
Id: 1,
Name: "Category1",
ParentId: 0,
},
{
Id: 5,
Name: "Sub-Category1",
ParentId: 1,
},
{
Id: 23,
Name: "Sub-Category2",
ParentId: 1,
},
{
Id: 50,
Name: "Category2",
ParentId: 0,
},
{
Id: 54,
Name: "Category3",
ParentId: 0,
},
];
I have tried many open source examples, but their json data format is not like mine. so that that are not useful for me. I have build something but that is not like my expected result. Here is my jsfiddle link what i have done.
https://jsfiddle.net/mrahman_cse/6wwan1fn/
Note: Every subcategory will goes under a category depend on "ParentId",If any one have "ParentId":0 then, it is actually a category, not subcategory. please see the JSON
Thanks in advance.
You can use this code jsfiddle
This example allows to add new nested categories, and do nested searching.
code with comments:
var SearchExample = React.createClass({
getInitialState: function() {
return {
searchString: ''
};
},
handleChange: function(e) {
this.setState({
searchString: e.target.value.trim().toLowerCase()
});
},
isMatch(e,searchString){
return e.Name.toLowerCase().match(searchString)
},
nestingSerch(e,searchString){
//recursive searching nesting
return this.isMatch(e,searchString) || (e.subcats.length && e.subcats.some(e=>this.nestingSerch(e,searchString)));
},
renderCat(cat){
//recursive rendering
return (
<li key={cat.Id}> {cat.Name}
{(cat.subcats && cat.subcats.length) ? <ul>{cat.subcats.map(this.renderCat)}</ul>:""}
</li>);
},
render() {
let {items} = this.props;
let {searchString} = this.state;
//filtering cattegories
if (searchString.length) {
items = items.filter(e=>this.nestingSerch(e,searchString))
console.log(items);
};
//nesting, adding to cattegories their subcatigories
items.forEach(e=>e.subcats=items.filter(el=>el.ParentId==e.Id));
//filter root categories
items=items.filter(e=>e.ParentId==0);
//filter root categories
return (
<div>
<input onChange={this.handleChange} placeholder="Type here" type="text" value={this.state.searchString}/>
<ul>{items.map(this.renderCat)}</ul>
</div>
);
}
});

Categories