Cannot read property 'columns' of undefined - javascript

I am trying to read json data from server and map. When I enter the same data with hand as a list to the code. It works. But when I am trying to read data from the server it does not work. I know problem is in mapping but I could not figure out. What can be the problem? This is code and json data. Thanks
class App extends Component {
constructor(props) {
super(props);
this.state = {
boards: {
id: null,
name: null,
owner: null,
columns:[]
}
};
}
getBoard() {
fetch("http://localhost:3001/boards/2")
.then(res => res.json())
.then(list => console.log(list))
.then(list => this.setState({boards: list}));
}
componentWillMount() {
this.getBoard();
}
{this.state.boards.columns.map((column, columnIndex) => (<Column
status={this.state.addModalShow}
onModalShow={this.onModalShow}
onHide={addModalClose}
addCard={this.addTask}
column={column}
columnIndex={columnIndex}
key={columnIndex}
onMoveLeft={cardIndex => this.handleMove(columnIndex, cardIndex, DIRECTION_LEFT)}
onMoveRight={cardIndex => this.handleMove(columnIndex, cardIndex, DIRECTION_RIGHT)}
onAddCard={() => this.handleAdd(columnIndex)}
deleteColumn={() => this.deleteColumn(columnIndex)}
addColumn={() => this.handleAdd()}
deleteTask={cardIndex => this.deleteTask(columnIndex, cardIndex)}/>))}
{
id: 2,
name: "Board3",
owner: "Ali",
-columns: [
-{
id: 5,
name: "eee",
cards: [
-{
id: 5,
name: "TestA",
description: "Desc",
link: "google.com",
deadline: "2013-04-06"
},
-{
id: 8,
name: "testB",
description: "Desc",
link: "google.com",
deadline: null
}
]
},
-{
id: 6,
name: "ff",
cards: []
}
]
}

But you don't return anything inside the function that prints the response to the console. Please read about Promise chaining.
Either return list in your second 'then' block or remove it completely.

Related

Next.js: getStaticPaths for nested dynamic routes

Imagine you have this data structure:
const data = {
posts: [{
id: 1,
title: "Post 1"
slug: "post-1"
}, {
id: 2,
title: "Post 2"
slug: "post-2"
}],
comments: [{
id: 1,
postId: "post-1",
text: "Comment 1 for Post 1"
}, {
id: 2,
postId: "post-1",
text: "Comment 2 for Post 1"
}, {
id: 3,
postId: "post-2",
text: "Comment 1 for Post 2"
}]
}
An you have the following route /posts/[postId[/[commentId]
so the Next.js structure folder is: posts/[postId]/[commented].js
Then you need to generate the static paths for this routes.
I'm coded the following:
export async function getStaticPaths() {
const { posts, comments } = data
const paths = posts.map((post) => {
return comments
.filter((comment) => comment.postId === post.slug)
.map((comment) => {
return {
params: {
postId: post.slug,
commentId: comment.id
}
}
})
})
}
But it's not working. The throwed error was:
Error: Additional keys were returned from `getStaticPaths` in page "/clases/[courseId]/[lessonId]". URL Parameters intended for this dynamic route must be nested under the `params` key, i.e.:
return { params: { postId: ..., commentId: ... } }
Keys that need to be moved: 0, 1.
How I can "map" or "loop" the data to a proper returned format?
Thanks in advance!
The problem seems to be that your returning this from getStaticPaths data with a wrong shape:
[
[ { params: {} }, { params: {} } ],
[ { params: {} } ]
]
The correct shape is:
[
{ params: {} },
{ params: {} },
{ params: {} }
]
Just tried this and it works.
export async function getStaticPaths() {
const paths = data.comments.map((comment) => {
return {
params: {
postId: comment.postId,
commentId: comment.id
}
}
});
console.log(paths);
return {
paths,
fallback: false
}
};
It generates 3 urls:
/posts/post-1/1
/posts/post-1/2
/posts/post-2/3
Is that what you need?
Like mention #Aaron the problem is for double array of filter y el map.
return {
paths: [
{ params: { id: '1' } },
{ params: { id: '2' } }
],
fallback: ...
}
Doc 📚 ➡ https://nextjs.org/docs/basic-features/data-fetching#the-paths-key-required

How to map through array of objects and list each object in a card using javascript and react?

i have the data structure like below,
const item = {
id: '1',
orders: [
{
id: '1',
title: 'order-1',
status: 'new',
startDate: '2020-08-13T00:00:00.000Z',
}
],
subItems: [
{
id: '1',
title: 'subitem-one',
status: 'new',
startDate: '2020-08-13T00:00:00.000Z',
orders: [
{
id: '1',
title: 'subitem1-order-one',
status: 'new',
},
{
id: '2',
title: 'subitem1-order-two',
status: 'new',
},
]
},
{
id: '2',
title: 'subitem-two',
status: 'new',
startDate: '2020-08-13T00:00:00.000Z',
orders: [
{
id: '2',
title: 'subitem2-order-one',
status: 'new',
},
},
I have to display each subitem name from above data in each card in a list.
below is how it should look in a list.
below is my code,
function Parent({items}: Props) {
//items is the same data as mentioned above
return (
//how should i map the items data to loop through each subitem and display it as in the picture above.
);
}
I am not sure how to loop through each subitem and display its name in a card using javascript and react.
could someone help me with this. thanks.
Ciao, assuming that you are using Card component from material ui you could do something like:
import { Card, CardHeader} from '#material-ui/core';
function Parent({items}: Props) {
//items is the same data as mentioned above
return (
items.subItems.map(el => {
<Card>
<CardHeader
title={el.title}
/>
</Card>
})
);
}
I'm assuming that Parent is a React functional component, so you can return the data in this way,
function Parent({items} : Props) {
return (
<div>
{
items.subItems.map(function (subItem) {
return <div>{subItem.title}</div>;
});
}
</div>
)
}
The template is shown below:
const Parent = () => {
const data = [...] // the data must be an array
return data.map(child => <Child data={child} />)
}

how to append object array to current state in react functional component

this is my state
const [dataItem, setDataItem] = useState({
id: null,
code: null,
title: null,
prent: null,
unitId: null,
});
and i want append file to dataItem state
let file = [
{
uid: '1',
name: items.file,
status: 'done',
},
];
setDataItem({ ...dataItem, file });
but it instead of append to dataItem , it replaced and other elements(e.g id, code, title) will be null
dataItem state after append file
{
"id": null,
"code": null,
"title": null,
"prent": null,
"unitId": null,
"file":[{
"uid": "1",
"name": "u104.svg",
"status": "done"
}]
}
Because the state was initialized to an object instead of an array. It should be
const [dataItem, setDataItem] = useState([{
id: null,
code: null,
title: null,
prent: null,
unitId: null,
}]);
When update dataItem, you have to spread array file too
setDataItem({ ...dataItem, ...file });
Read more =>
Correct modification of state arrays in ReactJS
To append file keeping the previous state intact, you'll need to use functional updates.
let file = [
{
uid: '1',
name: items.file,
status: 'done',
},
];
setDataItem(prevState => ({ ...prevState, file }));

Add object to nested array

I have initial state as
sites = [
{id, name, vehicles[], drivers[]},
{id, name, vehicles[], drivers[]},
{id, name, vehicles[], drivers[]},
{id, name, vehicles[], drivers[]},
];
I'm trying to add a vehicle to a given site when selected from a list which is in a component SiteVehcleSelection and the method that handles the selection is:
handleVehicleSelection = (event) => {
const vehicle = this.props.vehicles.find((v) => v.id === parseInt(event.target.dataset.id, 10));
this.props.handleVehicleSelection(event, this.state.site.id, {...vehicle});
};
which passes it up to parent SiteList method:
handleVehicleSelection = (event, siteId, vehicle) => {
this.props.dispatch(siteActions.handleVehicleSelect(siteId, vehicle), event.target.checked);
}
called from the SiteList class:
export function handleVehicleSelect(siteId, vehicle, cmd){
return (dispatch) => {
debugger;
return fetch(`${BASE_URL}/accounts/site-vehicle-action/${siteId}/${vehicle.id}/${cmd}`, {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: ''
}).then((res) => {
return res.json();
}).then((json) => {
if (json.msg === true) {
dispatch(vehicleSelect(siteId, vehicle));
}
});
}
}
which dispatches to this:
export function vehicleSelect(siteId, vehicle){
return {type: actionTypes.ADD_VEHICLE_TO_SITE, siteId, vehicle};
}
and my reducer is:
case actionTypes.ADD_VEHICLE_TO_SITE:
debugger;
const siteIndex = state.findIndex((site) => site.id === action.siteId);
console.log(state);
const newState = [...state.slice(0, siteIndex), {...state[siteIndex], vehicles: [...state[siteIndex].vehicles, action.vehicle],}, ...state.slice(siteIndex +1)];
console.log(newState);
return newState;
when I log before and after the changes have taken place, the vehicle has been added to the correct site but it does not show/refresh in the view here is the logging of the state before and after.
Before change :
0: {drivers: Array(0), id: 1, name: "Site One", vehicles: Array(0)}
1: {drivers: Array(0), id: 2, name: "Site Two", vehicles: Array(0)}
2: {drivers: Array(0), id: 3, name: "Site Three", vehicles: Array(0)}
length: 3
__proto__: Array(0)
After change:
0: {drivers: Array(0), id: 1, name: "Site One", vehicles: Array(1)}
1: {drivers: Array(0), id: 2, name: "Site Two", vehicles: Array(0)}
2: {drivers: Array(0), id: 3, name: "Site Three", vehicles: Array(0)}
length: 3
__proto__: Array(0)
can see the first one had the vehicle added correctly and this is the new state but nothing happens on return as if sitesList does not refresh.
Hope this edit helps explain more.
I think below code will shed some light. I assume you have the corresponding indexes.
let state = [
{ id: "id1", name: "name1", items: [{},{}] },
{ id: "id2", name: "name2", items: [{},{}] },
]
function reducer() {
switch("Action") {
case ADD_SITE: { // add new element to state
return [
...state,
payload.site,
]
}
case ADD_SITE_AT_INDEX: { // add new element to state at index: idx
return [
...state.slice(0, idx),
payload.newSite,
...state.slice(idx)
]
}
case ADD_ITEM: { // add new item to site with index: idx
return [
...state.slice(0, idx),
{
...state[idx],
items: [
...state[idx].items,
payload.newItem
],
},
...state.slice(idx+1)
]
}
case ADD_ITEM_AT_INDEX: { // add new item to site with index: idx, at item index: item_idx
return [
...state.slice(0, idx),
{
...state[idx],
items: [
...state[idx].items.slice(0, item_idx),
payload.newItem,
...state[idx].items.slice(item_idx),
],
},
...state.slice(idx+1)
]
}
}
}
let say this is your structure of state with keys (i am giving random name to the keys so i can explain)
{
data:[{id:"some_id",name:"some_name",items1:[{},{}]}]
}
//suppose this is your reducer code.
case ADD_ITEM:
return{
...state,
data: state.data.map(val=>{
if(val.Id===action.payload.Id){
return{
...val,
items1:[...val.items1,action.payload.data]
}
}
return{...val}
})
}
here you'll be sending Id and data from the action like:
{type:"ADD_ITEM",payload:{Id,data}}
where id will be the id of first level object which's array needs to be updated,
and data will be the data you want to add into the array..
If you just want to add an object to an array with a given structure, you can do this:
Structure
[
{ id, name, items1[{object},{object}]
]
copy an existing state and then add a new object to the end of the array.
return {
...state,
items1: state.items1.concat(action.newObject),
};
or with ES6 spread
return {
...state,
items1: [...state.items1, action.newObject],
};
// state: { id, name, items1: [{object},{object},{newObject}] }

Axios Async Multiple Request Vue.js Rendering Problem

I am trying to fetch data from different 2 json.
json for data1: [{ id: 1, name: 'abc'},{id:2, name: 'def'}] json for
data2: [{ product_id: 0001, },{product_id:0002}]
By using these I would like to create this kind of structure.
myStore = [ { id: 1, name: 'abc', products: [{ product_id: 0001,
},{product_id:0002}]}, { id: 2, name: 'def', products: [{ product_id:
0003, },{product_id:0004}]}
<script>
export default {
data: () => ({
myStore: [],
isLoaded: false,
}),
created(){
this.fetchData()
},
watch: {
'$route': 'fetchData'
},
methods: {
fetchData() {
axios.get('api/data1')
.then(response => {
this.myStore = response.data
})
.catch(error => {
console.log(error);
})
.then(() => {
this.myStore.forEach(subStore => {
axios.get('api/data2?substore_id=' + subStore.id)
.then(response => {
this.myStore.products = response.data
})
.catch(error => {
console.log(error);
})
});
})
this.isLoaded = true;
},
},
}
I checked console.log, the structure that I want to have is created correctly however the problem is about rendering.
I tried to render {{myStore}}, I can only see the first data (data1) results [{ id: 1, name: 'abc'},{id:2, name: 'def'}]
When I update any code without reload page (via F5), vue updates this change. This time I can see the structure correctly that I wanna have. But when I reload page all is gone.

Categories