I have some json data that looks like this:
{
"author1": {
"books": [{
"title": "title1"
},
{
"title": "title2"
}
],
"movies": [{
"title": "movie1"
},
{
"title": "movie2"
}
]
}
}
I want to have a dropdown that is populated with the authors (like author1). When that dropdown is selected, I then want to populate another dropdown with the keys for that author (books and movies).
So. if my json is in a variable named data, I want to populate the first dropdown with data.keys() and then the second with data[author].keys() where author is the value selected in the first dropdown.
I have seen a lot of examples of populating with json, but not with the keys. I am very new to React JS, so I am not sure how to do this.
Thanks
you can use the following flow.
const AuthorData = ({ symtomsData }) => {
const [data] = useState({
author1: {
books: [
{
title: "title1"
},
{
title: "title2"
}
],
movies: [
{
title: "movie1"
},
{
title: "movie2"
}
]
},
author2: {
books: [
{
title: "titleasd"
},
{
title: "titleqweqw"
}
],
movies: [
{
title: "movieqwewq"
},
{
title: "movieqweqwe"
}
]
}
});
const [authorWroks, setAuthorWorks] = useState({});
const [selectedData, setSelectedData] = useState([]);
const onChangeAuthor = useCallback(
(e) => {
const authorSelected = e.target.value;
if (authorSelected) {
setAuthorWorks(data[authorSelected]);
} else {
setAuthorWorks([]);
}
},
[data]
);
const changeItem = useCallback(
(e) => {
const itemSelected = e.target.value;
console.log("itemSelected", itemSelected);
if (itemSelected) {
console.log("authorWroks", authorWroks[itemSelected]);
setSelectedData(authorWroks[itemSelected]);
} else {
setSelectedData([]);
}
},
[authorWroks]
);
return (
<Grid>
<Col>
<select onChange={onChangeAuthor}>
<option value="">select</option>
{Object.keys(data).map((key, i) => (
<option value={key}>{key}</option>
))}
</select>
<br />
<div>
{Object.keys(authorWroks).length ? (
<select onChange={changeItem}>
<option value="">select</option>
{Object.keys(authorWroks || []).map((key, i) => (
<option onChange={changeItem} value={key}>
{key}
</option>
))}
</select>
) : undefined}
</div>
<div>
{selectedData.length ? (
<select>
<option value="">select</option>
{(selectedData || []).map((data, i) => (
<option onChange={changeItem} value={data.title}>
{data.title}
</option>
))}
</select>
) : undefined}
</div>
</Col>
</Grid>
);
};
Related
What I want is an example about how to make the drag and drop of my Table that works properly, but I cannot figure out how to make it works in (functional components)
My code :
function Preview() {
const { name } = useParams();
const [fieldsOfForm, setFieldsOfForm] = useState([]);
const [selectedForm, setSelectedForm] = useState([]);
const columns = [
{
title: 'Posição',
dataIndex: 'pos',
width: 30,
className: 'drag-visible',
render: () =>
<MenuOutlined style={{ cursor: 'grab', color: '#999' }}/>
},
{
title: "Form Name",
dataIndex: "field",
key: "field",
render: (text) => <a>{text}</a>,
},
{
title: "Tipo",
dataIndex: "fieldtype",
key: "fieldtype",
},
];
useEffect(() => {
let mounted = true;
let loadingStates = loading;
if (mounted) {
setFieldsOfForm(location.state);
loadingStates.allFields = false;
setLoading(false);
}
return () => (mounted = false);
}, [selectedForm]);
return (
//Some jsx....
<Row gutter={1}>
<Col span={1}></Col>
<Table dataSource={fieldsOfForm}
columns= {columns}/>
</Row>
// More jsx...
);
}
export default Preview;
Everything that I found on internet about this drag and drop from the lib of antd is in class component , but I wanted to make it works in my functional one.
Example that I found :
multi row drag-able table (antd)
I want some example in function component if someone has tried it already and could help me ?
Here's a functional working example:
import React from "react";
import "antd/dist/antd.css";
import { Table } from "antd";
import {
sortableContainer,
sortableElement,
sortableHandle
} from "react-sortable-hoc";
import { MenuOutlined } from "#ant-design/icons";
const data = [
{
key: "1",
name: "John Brown",
age: 32,
address: "New York No. 1 Lake Park",
index: 0
},
{
key: "2",
name: "Jim Green",
age: 42,
address: "London No. 1 Lake Park",
index: 1
},
{
key: "3",
name: "Joe Black",
age: 32,
address: "Sidney No. 1 Lake Park",
index: 2
},
{
key: "4",
name: "4",
age: 32,
address: "New York No. 1 Lake Park",
index: 3
},
{
key: "5",
name: "5",
age: 42,
address: "London No. 1 Lake Park",
index: 4
},
{
key: "6",
name: "6",
age: 32,
address: "Sidney No. 1 Lake Park",
index: 5
}
];
const DragHandle = sortableHandle(({ active }) => (
<MenuOutlined style={{ cursor: "grab", color: active ? "blue" : "#999" }} />
));
const SortableItem = sortableElement((props) => <tr {...props} />);
const SortableContainer = sortableContainer((props) => <tbody {...props} />);
function SortableTable() {
const [dataSource, setDataSource] = React.useState(data);
const [selectedItems, setSelectedItems] = React.useState([]);
const getColumns = () => {
return [
{
title: "Sort",
dataIndex: "",
width: 30,
className: "drag-visible",
render: (d, dd, i) => (
<>
<DragHandle active={selectedItems.includes(i)} />
</>
)
},
{
title: "Name",
dataIndex: "name",
className: "drag-visible"
},
{
title: "Age",
dataIndex: "age"
},
{
title: "Address",
dataIndex: "address"
}
];
};
const merge = (a, b, i = 0) => {
let aa = [...a];
return [...a.slice(0, i), ...b, ...aa.slice(i, aa.length)];
};
const onSortEnd = ({ oldIndex, newIndex }) => {
let tempDataSource = dataSource;
if (oldIndex !== newIndex) {
if (!selectedItems.length) {
let movingItem = tempDataSource[oldIndex];
tempDataSource.splice(oldIndex, 1);
tempDataSource = merge(tempDataSource, [movingItem], newIndex);
} else {
let filteredItems = [];
selectedItems.forEach((d) => {
filteredItems.push(tempDataSource[d]);
});
let newData = [];
tempDataSource.forEach((d, i) => {
if (!selectedItems.includes(i)) {
newData.push(d);
}
});
tempDataSource = [...newData];
tempDataSource = merge(tempDataSource, filteredItems, newIndex);
}
setDataSource(tempDataSource);
setSelectedItems([]);
}
};
const DraggableContainer = (props) => (
<SortableContainer
useDragHandle
disableAutoscroll
helperClass="row-dragging"
onSortEnd={onSortEnd}
{...props}
/>
);
const DraggableBodyRow = ({ className, style, ...restProps }) => {
// function findIndex base on Table rowKey props and should always be a right array index
const index = dataSource.findIndex(
(x) => x.index === restProps["data-row-key"]
);
return (
<SortableItem
index={index}
{...restProps}
selected={selectedItems.length}
onClick={(e) => {
if (e.ctrlKey || e.metaKey) {
selectedItems.includes(index)
? selectedItems.splice(selectedItems.indexOf(index), 1)
: selectedItems.push(index);
setSelectedItems(selectedItems);
} else {
setSelectedItems([]);
}
}}
/>
);
};
return (
<>
<h3>"CNTRL + Click" to select multiple items</h3>
<Table
pagination={false}
dataSource={dataSource}
columns={getColumns()}
rowKey="index"
components={{
body: {
wrapper: DraggableContainer,
row: DraggableBodyRow
}
}}
/>
{selectedItems.length ? <>{selectedItems.length} items selected </> : ""}
</>
);
}
You can play with it in Sandbox
Here, this app renders a chart like below-
As you can see there are two sidebars in the below app. I need the same chart to render again in the app. What I mean is that I need two of the chart that's been rendered. I think the chart that's rendered is drawn up with the below code but when I try to repeat the same code it won't render the same chart again.
<div class="divBar">
<canvas id="bar"></canvas>
</div>
As below, I even tried to change the canvas id here to a different id but it still won't rerender the chart -
<div class="divBar">
<canvas id="bar-duplicate"></canvas>
</div>
Below is the full app code-
How would I rerender another chart of the same kind that's showing? I need the second chart to render next to the second sidebar menu.
import React, { Component } from "react";
import { useState, useEffect } from "react";
import { FaBeer } from 'react-icons/fa';
import { Link } from 'react-router-dom';
//import { AiOutlineClose } from 'react-icons/ai';
import "./styles.css";
import { Chart } from "chart.js";
import moment from "moment";
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom';
import { ProSidebar, Menu, MenuItem, SubMenu } from 'react-pro-sidebar';
import 'react-pro-sidebar/dist/css/styles.css';
export default class App extends Component {
constructor(props) {
super(props);
this.levelsArr = [
"11/02/2011",
"12/02/2011",
"13/02/2011",
"14/02/2011",
"15/02/2011",
"16/02/2011",
"17/02/2011",
"18/02/2011"
];
this.chartData = {
dataSet1: Array.from(
{ length: 8 },
() => Math.floor(Math.random() * 590) + 10
),
dataSet2: Array.from(
{ length: 8 },
() => Math.floor(Math.random() * 590) + 10
)
};
this.state = {
months: [
{ month: "Jan", value: "0" },
{ month: "Feb", value: "1" },
{ month: "Mar", value: "2" },
{ month: "Apr", value: "3" },
{ month: "May", value: "4" },
{ month: "Jun", value: "5" },
{ month: "Jul", value: "6" },
{ month: "Aug", value: "7" }
],
dates: [
{ date: "11/02/2011", value: "0" },
{ date: "12/02/2011", value: "1" },
{ date: "13/02/2011", value: "2" },
{ date: "14/02/2011", value: "3" },
{ date: "15/02/2011", value: "4" },
{ date: "16/02/2011", value: "5" },
{ date: "17/02/2011", value: "6" },
{ date: "18/02/2011", value: "7" }
],
from: "0",
toMonth: "7",
fromDate: "0",
toDate: "7",
filterLimit: 100,
sidebarOpen: true,
sidebar: false
};
this.onSetSidebarOpen = this.onSetSidebarOpen.bind(this);
this.sidebar = this.showSidebar.bind(this);
}
onSetSidebarOpen(open) {
this.setState({ sidebarOpen: open });
}
showSidebar(sidebar) {
this.setState({sidebar: !sidebar});
}
componentDidMount() {
this.barChart = new Chart("bar", {
type: "bar",
options: {
responsive: true,
title: {
display: true,
text: "Student Admission Data"
}
},
data: {
labels: ["11/02/2011", "12/02/2011", "13/02/2011", "14/02/2011", "15/02/2011", "16/02/2011", "17/02/2011", "18/02/2011"],
datasets: [
{
type: "bar",
label: "School 1",
data: this.chartData.dataSet1,
backgroundColor: "rgba(20,200,10,0.4)",
borderColor: "rgba(20,200,10,0.4)",
fill: false
},
{
type: "bar",
label: "School 2",
data: this.chartData.dataSet2,
backgroundColor: "rgba(100,189,200,0.4)",
borderColor: "rgba(100,189,200,0.4)",
fill: false
}
]
}
});
}
applyFilter() {
//console.log(this.chartData.dataSet1);
const value = this.state.filterLimit;
const lessThanOrGreaterThan = this.state.lessThanOrGreaterThan;
console.log(lessThanOrGreaterThan);
this.barChart.data.datasets[0].data = this.chartData.dataSet1;
this.barChart.data.datasets[1].data = this.chartData.dataSet2;
this.barChart.data.datasets.forEach((data, i) => {
if (lessThanOrGreaterThan === "greaterThan") {
this.barChart.data.datasets[i].data = data.data.map((v) => {
if (v >= value) return v;
else return 0;
});
// console.log(">>>>>>>>", this.barChart.data.datasets[i].data);
} else {
this.barChart.data.datasets[i].data = data.data.map((v) => {
if (v <= value) return v;
else return 0;
});
//console.log("?????????", this.barChart.data.datasets[i].data);
}
});
this.barChart.update();
}
applyDateFilter() {
this.barChart.data.labels = this.levelsArr.slice(
parseInt(this.state.from),
parseInt(this.state.toMonth) + 1
);
this.barChart.update();
}
applyDaysFilter() {
this.barChart.data.labels = this.levelsArr.slice(
parseInt(this.state.fromDate),
parseInt(this.state.toDate) + 1
);
this.barChart.update();
}
render() {
return (
<div class="chart-diplay">
<div>
<React.StrictMode>
<div className = 'container'>
<div class="divSideBar">
<ProSidebar>
<Menu iconShape="square">
<MenuItem>
<select
id="lessThanOrGreaterThan"
value={this.state.lessThanOrGreaterThan}
onChange={(e) =>
this.setState({ lessThanOrGreaterThan: e.currentTarget.value })
}
>
<option value="lessThan">Less Than</option>
<option value="greaterThan">Greater Than</option>
</select>
</MenuItem>
<MenuItem>
<input
id="filterLimit"
placeholder="Filter Limit"
value={this.state.filterLimit}
onChange={(e) => this.setState({ filterLimit: e.target.value })}
></input>
</MenuItem>
<MenuItem>
<button class="button" onClick={() => this.applyFilter()}>
Apply Filter
</button>
</MenuItem>
<MenuItem>
<div>
<select
id="from"
value={this.state.from}
onChange={(e) => this.setState({ from: e.target.value })}
>
{this.state.months.map((el) => (
<option value={el.value} key={el}>
{" "}
{el.month}{" "}
</option>
))}
</select>
<select
id="toMonth"
value={this.state.toMonth}
onChange={(e) => this.setState({ toMonth: e.target.value })}
>
{this.state.months.map((el) => (
<option value={el.value} key={el}>
{" "}
{el.month}{" "}
</option>
))}
</select>
</div>
</MenuItem>
<MenuItem>
<button class="button" onClick={() => this.applyDateFilter()}>
Apply Months Filter
</button>
</MenuItem>
</Menu>
</ProSidebar>
</div>
<div class="divBar">
<canvas id="bar"></canvas>
</div>
</div>
</React.StrictMode>
</div>
<div>
<React.StrictMode>
<div className = 'containerTwo'>
<div class="divSideBar">
<ProSidebar>
<Menu iconShape="square">
<MenuItem>
<select
id="lessThanOrGreaterThan"
value={this.state.lessThanOrGreaterThan}
onChange={(e) =>
this.setState({ lessThanOrGreaterThan: e.currentTarget.value })
}
>
<option value="lessThan">Less Than</option>
<option value="greaterThan">Greater Than</option>
</select>
</MenuItem>
<MenuItem>
<input
id="filterLimit"
placeholder="Filter Limit"
value={this.state.filterLimit}
onChange={(e) => this.setState({ filterLimit: e.target.value })}
></input>
</MenuItem>
<MenuItem>
<button class="button" onClick={() => this.applyFilter()}>
Apply Filter
</button>
</MenuItem>
<MenuItem>
<div>
<select
id="from"
value={this.state.fromDate}
onChange={(e) => this.setState({ fromDate: e.target.value })}
>
{this.state.dates.map((el) => (
<option value={el.value} key={el}>
{" "}
{el.date}{" "}
</option>
))}
</select>
<select
id="toMonth"
value={this.state.toDate}
onChange={(e) => this.setState({ toDate: e.target.value })}
>
{this.state.dates.map((el) => (
<option value={el.value} key={el}>
{" "}
{el.date}{" "}
</option>
))}
</select>
</div>
<MenuItem>
<button class="button" onClick={() => this.applyDaysFilter()}>
Apply Days Filter
</button>
</MenuItem>
</MenuItem>
</Menu>
</ProSidebar>
</div>
</div>
</React.StrictMode>
</div>
</div>
);
}
}
Check this
create two chart object
two canvas element will render
on filter update you need to update your chart object and called update function
In the parent component manage-categories.jsx I have an array declared categoryTypes
const categoryTypes = [
{ name: "category", values: props.categories, active: true },
{ name: "type", values: props.types },
{ name: "finish", values: props.finishes },
{ name: "profile", values: props.profiles },
{ name: "thickness", values: props.thicknesses },
{ name: "ral", values: props.rals },
];
and a function selectItem that is called in the child component category-types-card.jsx
const selectItem = (item, category) => {
switch (category.name) {
case "category":
setSelectedCategoryItem(item);
break;
case "type":
setSelectedTypeItem(item);
break;
case "finish":
setSelectedFinishItem(item);
break;
case "profile":
setSelectedProfileItem(item);
break;
case "thickness":
setSelectedThicknessItem(item);
break;
case "ral":
setSelectedRalItem(item);
}
};
In the child component I need to show something for the categories that have active: true Category becomes active when it has an selectedItem.
I tried to make it active like categoryTypes[1] = { ...categoryTypes[1], active: true }; in the above switch, but in the child component the active property does not change for the certain category.
Calling the child component:
<Row className="mb-4">
{categoryTypes.map((category, index) => {
return (
<Colxx
xxs="12"
xs="6"
sm="6"
md="6"
lg="4"
xl="4"
xxl="4"
key={index}
>
<CategoryTypes
category={category}
employee={employee}
selectItem={selectItem}
selectedCategoryItem={selectedCategoryItem}
selectedTypeItem={selectedTypeItem}
selectedFinishItem={selectedFinishItem}
selectedProfileItem={selectedProfileItem}
selectedThicknessItem={selectedThicknessItem}
selectedRalItem={selectedRalItem}
/>
</Colxx>
);
})}
</Row>
How should I handle correctly this situation?
Thanks in advance!
How about passing a callback to the child component? Like so:
const ManageCategories = (props) => {
const [categoryTypes, setCategoryTypes] = useState([
{ name: "category", values: props.categories, active: true },
{ name: "type", values: props.types },
{ name: "finish", values: props.finishes },
{ name: "profile", values: props.profiles },
{ name: "thickness", values: props.thicknesses },
{ name: "ral", values: props.rals },
])
const setCategoryTypeActive = (categoryName, active) => {
setCategoryTypes((categoryTypes) =>
categoryTypes.map((categoryType) =>
categoryType.name === categoryName
? { ...categoryType, active }
: categoryType
)
)
}
return (
<Row className="mb-4">
{categoryTypes.map((category, index) => (
<Colxx xxs="12" xs="6" sm="6" md="6" lg="4" xl="4" xxl="4" key={index}>
<CategoryTypes
category={category}
employee={employee}
selectItem={selectItem}
selectedCategoryItem={selectedCategoryItem}
selectedTypeItem={selectedTypeItem}
selectedFinishItem={selectedFinishItem}
selectedProfileItem={selectedProfileItem}
selectedThicknessItem={selectedThicknessItem}
selectedRalItem={selectedRalItem}
setCategoryTypeActive={setCategoryTypeActive}
/>
</Colxx>
))}
</Row>
)
}
Then, somewhere in your child component, for example:
const CategoryTypesCard = (props) => {
props.setCategoryTypeActive("finish", true)
// ...
}
i need to display data in dropdown i haven given json data with code.
this.setState({
data : [
{id:1,type:A},
{id:1,type:B},
{id:1,type:C},
]
})
<select className="form-control" onChange={(e) => this.handleChange(e)} >
<option >Select data</option>
{
this.state.data.map((i, h) =>
(<option key={h} value={i.type}>{i.type}</option>))
}
</select>
Json isn't correct...put quotation for string type value-"A", "B", "C"
data: [{ id: 1, type: "A" }, { id: 1, type: "B" }, { id: 1, type: "C" }]
JSX
class App extends Component {
state = {
data: [{ id: 1, type: "A" }, { id: 1, type: "B" }, { id: 1, type: "C" }]
};
handleChange = e => {
console.log(e.target.value);
};
render() {
return (
<div>
<select className="form-control" onChange={this.handleChange}>
<option>Select data</option>
{this.state.data.map((i, h) => (
<option key={h} value={i.type}>
{i.type}
</option>
))}
</select>
</div>
);
}
}
I am using react-select to store multiple elements and am using the map function to display elements which is working fine. But when I am using the same element in another class to display in a list element it shows a blank.
Here is the code where I am displaying the multiple options.
const Departments = [
{ label: "OneIT", value: "OneIT" },
{ label: "HR", value: "HR" },
{ label: "Vigilance", value: "Vigilance" },
{ label: "Ethics", value: "Ethics" },
{ label: "Corporate Services", value: "Corporate Services" },
{ label: "Legal", value: "Legal" },
{ label: "Sports", value: "Sports" },
{ label: "TQM", value: "TQM" },
{ label: "Iron Making", value: "Iron Making" },
{ label: "TMH", value: "TMH" }
];
class MultiSelect2 extends Component {
state = {
selectedOptions: []
};
handleChangeField = selectedOptions => {
this.setState({ selectedOptions });
};
render() {
const { selectedOption } = this.state;
return (
<div className="container">
<div className="row">
<div className="col-md-2"></div>
<div className="col-md-8">
<span>Select Department</span>
<Select
value={selectedOption}
options={Departments}
onChange={this.handleChangeField}
isMulti
/>
{this.state.selectedOptions.map(o => (
<p>{o.value}</p>
))}
</div>
<div className="col-md-4"></div>
</div>
</div>
);
}
}
I am trying to display this in another class in the list item but it is not showing.
export class Confirm extends Component {
state = {
selectedOptions: []
};
render() {
const {
values: {selectedOptions
}
} = this.props;
return (
<List>
<ListItemText primary="Departments" secondary={selectedOptions} />
</List>