I need to render data using React vertical tabs, I have given code which I have tried and also the data coming from API. I am not getting how to loop inside <TabPanel>.
link for codesandbox https://codesandbox.io/s/jovial-darkness-qob1n?file=/src/tab.js
<Tabs
defaultTab="vertical-tab-one"
vertical
className="vertical-tabs"
>
<TabList>
{subProducts.map((subProduct, index) => (
<Tab>{subProduct.subProductName}</Tab>
))}
</TabList>
{subProducts.map((subProduct, index) => (
<TabPanel className="tab-pane fade mt-4 show ">
{subProduct.bookingDetails.map((attr, i) => (
<>
<table id="customers">
<tbody>
<tr>
<td>{attr.name}</td>
<td>{attr.value}</td>
</tr>
</tbody>
</table>
</>
))}
</TabPanel>
))}
</Tabs>
API output:
subProducts: [
{
bookingDetails: [
{
name: "Birthday Decoration",
value: "YES"
},
{
name: "Photographer",
value: "NO"
}
],
subProductName: "Celebration"
},
{
bookingDetails: [
{
name: "Decoration",
value: "YES"
},
{
name: "Video",
value: "NO"
}
],
subProductName: "FamilY"
}
]
In the sandbox you try to map over bookingDetails for each object in the subProducts array, but in the second object of subProducts you have a Details property, but not a bookingDetails property so bookingDetails will be undefined.
So you probably want to change Details to bookingDetails:
subProducts: [
{
bookingDetails: [
{
name: "Birthday Decoration",
value: "YES",
},
{
name: "Photographer",
value: "NO",
},
],
subProductName: "Celebration",
},
{
bookingDetails: [
{
name: "Decoration",
value: "YES",
},
{
name: "Video",
value: "NO",
},
],
subProductName: "FamilY",
},
];
If the API returns Details instead of bookingDetails as in your original question do it the other way around. Change it so it maps over Details instead:
So subProduct.Details.map instead of subProduct.bookingDetails.map.
The data not being displayed correctly on click is because each Tab component need to have a tabFor prop value that corresponds with a TabPanel's tabId prop value. Otherwise react-web-tabs doesn't know what content to show when.
For this example I've used the map's index and called toString on it before passing it to the props as the id needs to be a string. But a more natural id would be to have id fields in your data and use those.
Example Sandbox
Related
There is a JSON for categories with the following structure
[
{
"category": "Mobiles",
"sub": [
{
"name": "Apple"
},
{
"name": "Samsung"
}
]
},
{
"category": "Televisions",
"sub": [
{
"name": "Lg"
},
{
"name": "Sony"
}
]
}
]
First i load data from backend to a variable called categories (On the backend side im using expressjs and pass data with res.json(JSON.parse(fs.readFileSync('categories.json')))
I want to iterate through categories sub category with
{categories.map(function (category, i) {
return (
<>
<h6 Key={i}>{category.category}</h6> //For example: <h6>Mobiles</h6>
<>... [logic to iterate the current category's sub categories] ...</> //For example: <p>Apple</p> <p>Samsung</p>
</>
);
})}
I tried to use a second map on category.sub like category.sub.map((s,j)=><p Key={j}>{s.name}</p>) but unfortunely i can't get it work, and I can't describe my problem to Google in English so it can be an easy answer and i am the big L
Any help?
Thanks
Try this, uncomment out the console.log to verify data if screen is white.
return (
<>
{categories.map(function (category, i) {
// console.log(category.category );
// console.log(category.sub );
return (
<>
<h6 key={i}>{category.category}</h6>
<>
{category.sub.map(function (sub, j) {
// console.log(category.category + '' + sub.name);
return <p key={j}> {sub.name}</p>;
})}
</>
</>
);
})}
</>
);
Data:
let categories = [
{
category: 'Mobiles',
sub: [
{
name: 'Apple',
},
{
name: 'Samsung',
},
],
},
{
category: 'Televisions',
sub: [
{
name: 'Lg',
},
{
name: 'Sony',
},
],
},
];
In a list of certain records where I'm populating in the dropdown of an input component. The default value is set on page loading but, I need to update it on click event of a button. Refer to the code below.
Home.js
const allList = [
{ id: "1", value: "Fruits" },
{ id: "2", value: "Vegetables" },
{ id: "3", value: "Grains" },
{ id: "4", value: "Milk" },
{ id: "5", value: "Meat" },
{ id: "6", value: "Fish" },
{ id: "7", value: "Pulses" }
];
const [itemList, setItemList] = useState(allList);
const [newValue, setNewValue] = useState(allList[0].value)
// I want to set the value on click of cancel button
const handleCancel = (e) => {
setNewValue(allList[2].value)
setPopup(false);
};
return (
<>
<DataList
defaultValue={newValue}
list="itemListOptions"
id="itemList"
placeholder="Search/select items"
data={itemList}
onSelectionChange={itemChanged}
></DataList>
{popup === true ? (
<Popup okbtnClick={handleOK} canclebtnclick={handleCancel} />
) : null}
</>
)
DataList.js
<input
defaultValue={props?.defaultValue ?? ""}
className="form-control cpselect"
id={props?.id ?? ""}
list={props?.list ?? ""}
placeholder={props?.placeholder ?? ""}
onChange={props?.onSelectionChange ?? ""}
/>
<datalist key={props.id} id={props?.list ?? ""}>
{props.data.map((d) => {
return <option key={d.id} id={d.id} value={d.value}></option>;
})}
</datalist>
My intention is to change the defaultValue inside the input field, on click of cancel button. Here it loads the first element and on click event should load third element. What is the best optimal solution?
Please refer to the Codesandbox link: https://codesandbox.io/s/clever-rumple-ig0wwj
What you want to do is to use value instead of defaultValue.
defaultValue property is configured in such a way that it reads the prop only once and then creates an inner state that handles changes.
I'm a react.js beginner, searching for methods to alter my data structure. For example, I want to push new objects into the children-array or remove them by key.
What is the appropriate way to do that?
const [treeData, setTreeData] = useState([
{
title: "parent 1",
key: "0-0",
icon: <UserAddOutlined />,
children: [
{
title: "parent 1-0",
key: "0-0-0",
icon: <UserAddOutlined />,
children: [
{
title: "leaf",
key: "0-0-0-0",
icon: <UserAddOutlined />,
},
{
title: "leaf",
key: "0-0-0-1",
icon: <UserAddOutlined />,
},
],
},
{
title: "parent 1-1",
key: "0-0-1",
icon: <UserAddOutlined />,
children: [
{
title: "sss",
key: "0-0-1-0",
icon: <UserAddOutlined />,
},
],
},
],
},
]);
So you should not update the state directly. It is not allowed.
Maybe where you are receiving data from, suppose via api and the data is response.payload.data etc.
So in your case use the setTreeData(response.payload.data) method to add stuff in it.
Now if you want to update certain value (remove or update using index etc). Obviously you will have to have index somehow.
So for deleting say you will have some click and against that a handler for it
removeItem(e) {
item_to_remove = e.target..... etc // to get the item's reference for matching
setTreeData(treeData.filter(items => item.<someproperty> != item_to_remove))
// In your case could also be targetting children maybe
// setTreeData(treeData.Children.filter(items => item.<someproperty> != item_to_remove))
}
I would say maybe handle childrens' array inside another useState variable (childrenTreeData maybe). But you will have to look it's feasibility too. Just an idea after seeing your data
JUST for INFO
This is something similar I did for updating prices inside each cards in my project
const getCurrentPrice = useCallback(() => { // <======= maybe you do not need this
const updatedTilesData = tilesData.map((tile: any) => {
return {
...tile, // <======= get everything here and then update the price below for item
currentPrice: calculateDNCurrentPrice(
tile.startingPrice,
tile.dnTimestamp
),
};
});
setTilesData(updatedTilesData);
}, [tilesData]);
I'm trying to use an object key to set the name of a column in MUI Datatables.
I'm trying to set one of the column names with the first element of children.childName
so that in that column it will display list of child names, but only the first child.
In Current way that Im trying this, I am getting no errors, and its displaying nothing in the childName Column on the table.
How Can I access an object thats inside an array?
This is my Data:
const data = [
{
name: "Pat",
company: "Test Corp",
city: "Yonkers",
state: "NY",
children: [
{ childName: "Pat Jun", childAge: 2 },
{ childName: "Mary Jun", childAge: 2 }
]
},
];
const columns = [
{
name:name: data[0]["children"][0]["childName"],
label: "Child Name",
options: {
filter: true,
sort: true
}
}]
MuiTable.js
function MuiTable({ forms }) {
console.log("cols", columns);
return (
<MUIDataTable
title={"Title"}
data={data}
columns={columns}
options={options}
/>
);
}
By doing a console.log I can see that it is printing the value instead of the object key name
I would really appreciate any help, Thank you.
You need to use customBodyRender like this:
import React from "react";
import ReactDOM from "react-dom";
import MUIDataTable from "mui-datatables";
import { Typography } from "#material-ui/core";
import "./styles.css";
function App() {
const data = [
{
name: "Pat",
company: "Test Corp",
city: "Yonkers",
state: "NY",
children: [
{ childName: "Pat Jun", childAge: 2 },
{ childName: "Mary Jun", childAge: 2 }
]
}
];
const columns = [
{
name: "children",
label: "Child Names",
options: {
filter: true,
sort: true,
customBodyRender: (value, tableMeta, updateValue) => (
<Typography>
{value.map(child => child.childName).join(",")}
</Typography>
)
}
}
];
return (
<div>
<MUIDataTable title={"Title"} data={data} columns={columns} />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Thanks very much to #Klaus your answer. That's pretty much what I had to do, but In my case, I wanted to only display the first childName in the object children which was in an array of objects.
So I had to adapt it a bit and change my data structure as well.
This is what I ended up doing.
I first added a simple array to my data structure completely seperate to the array containing the children objects called childNames, which just came contained only the names.
This made it alot easier to access the childNames as it was just a simple array not nested in anything.
So I simply just displayed the first element in the array on Table
const columns = [
{
name: "childNames",
label: "Child Name",
options: {
filter: true,
customBodyRender: (value, tableMeta, updateValue) => {
return <div>{value[0]}</div>;
}
}
},
The reason why I created an array for just childNames, was because trying to access only just the first childName in the array containing children objects was proving very complicated and difficult.
Thanks very much for all the help.
The form has radio buttons which generate question from answers:[{}] it save based ononChage to the answers:[{}] as selected.
Demo: https://codesandbox.io/s/mm4qrv4o6j
Current status of the questions and answers are
const question = {
questions: {
questionID: 1,
title: "Your gender ?",
values: [{ id: "1", value: "Male" }, { id: "2", value: "Female" }]
}
};
this.state = {
answers: [
{
questionID: "1",
answerValues: "2"
}
]
};
Unfortunately not able to update the answer because the radio onChange doesn't allow to change
<div className="form-group">
<label htmlFor={name}>{label}</label>
{options.map(option => {
return (
<div className="form-check" key={option.id}>
<label className="radio-inline" htmlFor={`${name}-${option.id}`}>
<input
name={name}
id={`${name}-${option.id}`}
data-question-id={questionID}
type="radio"
onChange={onChange}
value={option.id}
checked={option.id == checked.questionID}
/>{" "}
{option.value}
</label>
</div>
);
})}
</div>
One thing to note this structure doesn't seem suitable for when you add more questions/answers (an array is probably more suitable):
answered: {
answers: {
questionID: "1",
answerValues: "1"
}
}
The first and main issues is that your root component that controls when the sub ones are going to re-render, is never re-rendered itself. To solve this you can use local state to update answers:
const question = {
questions: {
questionID: 1,
title: "Your gender ?",
values: [{ id: "1", value: "Male" }, { id: "2", value: "Female" }]
}
};
class App extends React.Component {
state = {
answered: {
answers: {
questionID: "1",
answerValues: "1"
}
},
}
updateAnswer = (newAnswer) => {
this.setState({
answered: {
answers: newAnswer,
},
});
}
render () {
return(
<div style={styles}>
<h2>Start editing to see some magic happen {"\u2728"}</h2>
<hr />
<FormQuestion question={question.questions} answered={this.state.answered.answers} updateAnswer={this.updateAnswer}/>
</div>
)
}
};
The final issue is that the checked ID is in a confusingly named "answerValues", not "questionID", so change to:
checked={option.id === checked.answerValues}
Working demo: https://codesandbox.io/s/62ovz1kql3
I would suggest you to refactor your solution and put inputs inside the form tag. Then simply remove onChange from the Radio and add it to the form. Then just run your code again.