show form in dynamic column when iterating - javascript

I have a long form which has mixed type of column. I mean some field will be of width 100% some field will be around 33% so that i can show 3 fields in a column and so on. This I could do without iterating, but how can it be done if the fields are shown with iteration to avoid code repetition? I have created a sandbox either and I am not using third party css framework like bootstrap just a flex or may be grid would work.
Here is how i have tried:
const formFields = [
{ id: 1, name: "first_name", component: TextField, label: "First Name" },
{ id: 1, name: "last_name", component: TextField, label: "Last Name" },
{ id: 1, name: "age", component: TextField, label: "Age" },
{ id: 1, name: "city", component: TextField, label: "City" },
{ id: 1, name: "state", component: TextField, label: "State" },
{ id: 1, name: "country", component: TextField, label: "Country" }
];
const FlexibleForm = () => {
return (
<React.Fragment>
<Form onSubmit={() => console.log("something")}>
<FlexRow>
<FlexColumn size={12}>
{formFields.map(({ id, name, label, component }) => {
return (
<Field
key={id}
name={name}
label={label}
component={component}
/>
);
})}
</FlexColumn>
</FlexRow>
<h2>Another without iteration</h2>
<FlexRow>
<FlexColumn size={6}>
<Field name="first_name" label="First Name" component={TextField} />
</FlexColumn>
<FlexColumn size={6}>
<Field name="last_name" label="Last Name" component={TextField} />
</FlexColumn>
</FlexRow>
<FlexRow>
<FlexColumn size={12}>
<Field name="age" label="Age" component={TextField} />
</FlexColumn>
</FlexRow>
<FlexRow>
<FlexColumn size={4}>
<Field name="city" label="City" component={TextField} />
</FlexColumn>
<FlexColumn size={4}>
<Field name="state" label="State" component={TextField} />
</FlexColumn>
<FlexColumn size={4}>
<Field name="country" label="Country" component={TextField} />
</FlexColumn>
</FlexRow>
</Form>
</React.Fragment>
);
};
export default reduxForm({
form: "form"
})(FlexibleForm);
export const FlexRow = styled.div`
display: flex;
div {
margin-right: 10px;
}
`;
export const FlexColumn = styled.div`
width: ${props => (props.size / 12) * 100}vw;
`;
Here is the codesandbox link https://codesandbox.io/s/l7lm1qp0pq

This is <FlexRow> component
const FlexRow = props => {
return (
<div style={{ display: "flex" }}>
{props.elements.map((element, index) => {
const obj = element.component;
return (
<FlexColumn key={index} size={Math.round(12 / props.elements.length)}>
<Field
name={element.name}
label={element.label}
component={obj[Object.keys(obj)[0]]}
/>
</FlexColumn>
);
})}
</div>
);
};
This is <FlexColumn> component
const FlexColumn = styled.div`
width: ${props => (props.size / 12) * 100}vw;
margin-right: 10px;
`;
Your <FlexibleForm> should look like this :
const FlexibleForm = () => {
return (
<React.Fragment>
<Form onSubmit={() => console.log("something")}>
<FlexRow
elements={[
{ name: "first_name", label: "First Name", component: {TextField} },
{ name: "last_name", label: "Last Name", component: {TextField} }
]}
/>
<FlexRow
elements={[{ name: "age", label: "Age", component: {TextField} }]}
/>
<FlexRow
elements={[
{ name: "city", label: "City", component: {TextField} },
{ name: "state", label: "State", component: {TextField} },
{ name: "country", label: "Country", component: {TextField} }
]}
/>
</Form>
</React.Fragment>
);
};
The component <FlexRow> will loop inside his props elements and will create a <FlexColumn> with the good size with the good attributes.
Litteraly, it did loop inside the props elements which is an array and return the size (12 divided by the number of rows you have), you can change this value if you want with a simple condition like :
element.size ? element.size : Math.round(12 / props.elements.length)
and add a size element in your elements array
{ name: "first_name", label: "First Name", size: 6, component: {TextField} }
Then it add the label and the name. And finally it add the component you choosed, in this example it's <TextField>
This will avoid you from repeating your code.
Here's the CodeSandBox to show you the example !
Wish I did helped you.

There is no much point of using flex if you are not using flex-wrap.
If you want to do it with simple float:
const formFields = [
{ id: 1, name: "first_name", component: TextField, label: "First Name",size: 6 },
{ id: 1, name: "last_name", component: TextField, label: "Last Name", size: 6 },
{ id: 1, name: "age", component: TextField, label: "Age", size: 12 },
{ id: 1, name: "city", component: TextField, label: "City", size: 4 },
{ id: 1, name: "state", component: TextField, label: "State", size: 4 },
{ id: 1, name: "country", component: TextField, label: "Country", size: 4 }
];
const Form = styled.form`
width: 100%;
`;
const FlexColumn = styled.div`
float: left;
width: ${props => (props.size / 12) * 100}%;
`;
const FlexibleForm = () => (
<React.Fragment>
<Form onSubmit={() => console.log("something")}>
{formFields.map(({ id, name, label, component, size }) => {
return (
<FlexColumn size={size}>
<Field key={id} name={name} label={label} component={component} />
</FlexColumn>
);
})}
</Form>
</React.Fragment>
);

Related

Get key from datalist in Form.Control

I get from the API a json, with a list of each staff member:
const MOCK_STAFF = [{
id: 1,
name: "Jhon Doe",
department: "HR"
}, {
id: 2,
name: "Jane Doe",
department: "Research"
}, etc
Then they get mapped in a datalist <option>, inside a Form.Control component:
<Form.Group className="mb-3">
<Form.Label>Name</Form.Label>
<Form.Control
name='staffName'
value={0}
list="namesList"
onChange={(e) => onChangeHandler(e)}/>
<Form.Label>Department</Form.Label>
<Form.Control disabled
name=department
value={}
/>
<datalist id="namesList">
{MOCK_DATA.map( (data) => (
<option key={data.id} value={data.department}>{data.name}</option>
))}
</datalist>
</Form.Group>
sandbox link: https://codesandbox.io/s/modal-t59e7z?file=/src/App.tsx
I would like the onChange={(e) => onChangeHandler(e)} to get the data-value of <option key={data.id} on form submit, and to make the department Form.Control to reference the value of <option value={data.department} in the datalist. The 'key' id must not show to the user, it is used as a primary key on the database.
I have tried:
function onChangeHandler(e:React.SyntheticEvent) {
console.log(e.target.key);
}
but "property key does not exist on event.target". Nor I can use document.getElementById(); with react. How can I get the values 'key', 'value' and/or 'default-value` from a Form.Control with a datalist?
Thank you
I could not achieve this with data-list, but did so with react-select:
type StaffOption = {
label: string, value: number
}
const MOCK_DATA= [{
id: 1,
name: "Jhon Doe",
department: "HR"
}, {
id: 2,
name: "Jane Doe",
department: "Research"
}, {
id: 3,
name: "Elizabeth meyer",
department: "Operations"
}]
type NameOption = {value: number, label: string, department: string}
type NameOptions = Array<NameOption>
function AddNewRowModal(props:AddNewRowProps) {
const [selectedStaffID, setSelectedStaffID] = useState(0);
function onChangeHandler(option: OnChangeValue<StaffOption, false>,
actionMeta: ActionMeta<StaffOption>) {
console.log(option); //this returns all 3 values defined on type StaffOption
if (option?.value !== undefined) {
setSelectedStaffID(option.value!);
}
}
function BuildOptions (data:any[]) {
var options:NameOptions = []
data.forEach(element => {
options.push({
value: element.id!,
label: (element.name),
department: element.department});
});
return options;
var nameOptions = BuildOptions(MOCK_DATA);
return (
<Modal
show={props.showModal}
backdrop="static"
keyboard={false}
onHide={() => props.closeModal()} >
<Modal.Header closeButton>
<Modal.Title>Add new Entry</Modal.Title>
</Modal.Header>
<Modal.Body>
<Select
options={nameOptions}
onChange={onChangeHandler} />
</Modal.Body>
<ModalFooter>
<Button variant='primary'>Create Entry</Button>
<Button variant='danger' onClick={() => props.closeModal()}>Cancel</Button>
</ModalFooter>
</Modal>
);
}
And the codesandbox

ReactJS mapped choices array based on id

I am pretty new to JavaScript and was hoping someone could help me out with this one.
I have this page that shows all the scheduled exams and when you press on "Learn more" a modal opens up that should let you modify information about the exam itself. At the moment it shows the equipment that is selected when creating the exam plus the rest of the equipment available and you should be able to select/deselect in order to change if needed. The problem is that a different modal opens up for each exam to show the corresponding data only. All the exam information I've got shown through mapping to get to the inside arrays of the "exams" nested array, so I do not know how to initialize a const before the render when I need the modal to be open to get that specific exams' info. At the moment I am mapping the values of the selected equipment which does not let me change the selection like I should.
https://codesandbox.io/s/81xer5
import "./styles.css";
import React, { useState, useEffect } from "react";
import Box from "#mui/material/Box";
import Card from "#mui/material/Card";
import CardActions from "#mui/material/CardActions";
import CardContent from "#mui/material/CardContent";
import Button from "#mui/material/Button";
import Typography from "#mui/material/Typography";
import Modal from "#mui/material/Modal";
import Chip from "#mui/material/Chip";
import OutlinedInput from "#mui/material/OutlinedInput";
import InputLabel from "#mui/material/InputLabel";
import MenuItem from "#mui/material/MenuItem";
import FormControl from "#mui/material/FormControl";
import Select from "#mui/material/Select";
const ITEM_HEIGHT = 48;
const ITEM_PADDING_TOP = 8;
const MenuProps = {
PaperProps: {
style: {
maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
width: 250
}
}
};
const style = {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
boxShadow: 24,
p: 4,
borderRadius: 1
};
export default function App() {
const [exams, setExams] = useState([
{
id: "18897a8c-bd5b-4fc0-86d1-74ee509d46ee",
name: "New Test",
date: null,
time: null,
date2: "2022-06-20",
time2: "15:30",
students: [
{
id: "749ce920-2462-457a-8af3-26ff9c00dda5",
username: "student1",
email: "student1#gmail.com",
firstName: "Student",
lastName: "Studentov",
roleName: "STUDENT"
},
{
id: "90289548-19bb-480b-81e3-c36340debbc7",
username: "student2",
email: "student2#gmail.com",
firstName: "Student",
lastName: "Studentov",
roleName: "STUDENT"
},
{
id: "dfe50fe5-ef9d-480e-aa6c-2f5c81bb22da",
username: "student3",
email: "student3#gmail.com",
firstName: "Student",
lastName: "Studentov",
roleName: "STUDENT"
}
],
staff: [
{
id: "a3b53ed0-63fc-4f77-a8dc-74915d6aefea",
username: "staff",
email: "staff#gmail.com",
firstName: "Staff",
lastName: "Staffov",
roleName: "STAFF"
}
],
rooms: [
{
id: "a49f18cb-4fe8-4a2c-a665-4361c5401f31",
number: 100,
nrOfSeats: 20
},
{
id: "5c46e888-fce4-4c1b-a8ec-e04d32a5cf6c",
number: 400,
nrOfSeats: 10
}
],
equipment: [
{
id: "08506d1b-30ce-43d2-a0b8-74f87082e356",
name: "Crane",
availability: true
}
]
},
{
id: "65b7ecd2-ba30-4369-9f13-9186dc5cc73c",
name: "Crane Exam",
date: null,
time: null,
date2: null,
time2: null,
students: [
{
id: "749ce920-2462-457a-8af3-26ff9c00dda5",
username: "student1",
email: "student1#gmail.com",
firstName: "Student",
lastName: "Studentov",
roleName: "STUDENT"
},
{
id: "90289548-19bb-480b-81e3-c36340debbc7",
username: "student2",
email: "student2#gmail.com",
firstName: "Student",
lastName: "Studentov",
roleName: "STUDENT"
},
{
id: "dfe50fe5-ef9d-480e-aa6c-2f5c81bb22da",
username: "student3",
email: "student3#gmail.com",
firstName: "Student",
lastName: "Studentov",
roleName: "STUDENT"
}
],
staff: [
{
id: "a3b53ed0-63fc-4f77-a8dc-74915d6aefea",
username: "staff",
email: "staff#gmail.com",
firstName: "Staff",
lastName: "Staffov",
roleName: "STAFF"
}
],
rooms: [
{
id: "a49f18cb-4fe8-4a2c-a665-4361c5401f31",
number: 100,
nrOfSeats: 20
},
{
id: "5c46e888-fce4-4c1b-a8ec-e04d32a5cf6c",
number: 400,
nrOfSeats: 10
}
],
equipment: [
{
id: "08506d1b-30ce-43d2-a0b8-74f87082e356",
name: "Crane",
availability: true
},
{
id: "be1da3c9-7192-459f-bdba-767e005eaac9",
name: "Killer Robot",
availability: true
}
]
}
]);
const [equipment, setEquipment] = useState([
{
id: "08506d1b-30ce-43d2-a0b8-74f87082e356",
name: "Crane",
availability: true
},
{
id: "7a1716c7-3398-4e3d-9523-7ba4a102a79b",
name: "Lift",
availability: true
},
{
id: "be1da3c9-7192-459f-bdba-767e005eaac9",
name: "Killer Robot",
availability: true
}
]);
const initialShowState = Object.fromEntries(
exams.map((data) => [data.id, false])
);
const [show, setShow] = React.useState(initialShowState);
const toggleShow = (id) =>
setShow((prev) => {
return { ...prev, [id]: !prev[id] };
});
console.log({ show });
const [value, setValue] = React.useState([]); //this is what the select chip uses by default
const handleChange = (e) => {
const {
target: { value }
} = e;
console.log(value);
setValue(
// On autofill we get a the stringified value.
typeof value === "string" ? value.split(",") : value
);
};
return (
<div className="App">
{exams.map((data, key) => {
return (
<div key={key} style={{ width: "300px", display: "inline-block" }}>
<Box
sx={{
minWidth: 300,
maxWidth: 300,
display: "inline-block",
paddingTop: "10px",
paddingLeft: "10px"
}}
>
<Card variant="outlined">
<React.Fragment>
<CardContent>
<Typography variant="h5" component="div">
{data.name}
</Typography>
</CardContent>
<CardActions>
<Button size="small" onClick={() => toggleShow(data.id)}>
Learn More
</Button>
</CardActions>
</React.Fragment>
</Card>
</Box>
<Modal open={show[data.id]} onClose={() => toggleShow(data.id)}>
<Box sx={style}>
<Typography
component={"span"}
id="transition-modal-description"
sx={{ mt: 2 }}
>
<FormControl sx={{ m: 1, width: 300 }}>
<InputLabel id="demo-multiple-chip-label">Chip</InputLabel>
<Select
multiple
value={data.equipment.map((sub) => sub.id)}
// value={value}
onChange={handleChange}
input={
<OutlinedInput id="select-multiple-chip" label="Chip" />
}
renderValue={(selected) => {
return (
<Box
sx={{ display: "flex", flexWrap: "wrap", gap: 0.5 }}
>
{selected.map((value) => {
const option = equipment.find(
(o) => o.id === value
);
return <Chip key={value} label={option.name} />;
})}
</Box>
);
}}
MenuProps={MenuProps}
>
{equipment.map((option) => (
<MenuItem key={option.id} value={option.id}>
{option.name}
</MenuItem>
))}
</Select>
</FormControl>
</Typography>
</Box>
</Modal>
</div>
);
})}
</div>
);
}
Continuing my comment above, you're adding a <Modal> inside the map function, this will mount a <Modal> element for each exam, which is bad for performance and more difficult to implement.
What you want to do is to have only one modal, and upon clicking "Learn More" you save the active exam in a state, the modal uses this state to show the correct data. You also want to split the logic between the exam and the modal to make it more easy to implement.
Here is a sample code, I have moved the arrays outside the component to make the code more clear:
const EXAMS = [...];
const EQUIPMENTS = [...];
export default function App() {
const [exams, setExams] = useState(EXAMS);
const [equipment, setEquipment] = useState(EQUIPMENTS);
const [modalExam, setModalExam] = useState(null);
return (
<div className="App">
{exams.map((data, key) => {
return (
<div key={key} style={{ width: "300px", display: "inline-block" }}>
<Box
sx={{
minWidth: 300,
maxWidth: 300,
display: "inline-block",
paddingTop: "10px",
paddingLeft: "10px",
}}
>
<Card variant="outlined">
<React.Fragment>
<CardContent>
<Typography variant="h5" component="div">
{data.name}
</Typography>
</CardContent>
<CardActions>
<Button size="small" onClick={() => setModalExam(data)}>
Learn More
</Button>
</CardActions>
</React.Fragment>
</Card>
</Box>
</div>
);
})}
<ModalExam
equipment={equipment}
exam={modalExam}
onClose={() => setModalExam(null)}
/>
</div>
);
}
function ModalExam({ exam, equipment, onClose }) {
const [chipValue, setChipValue] = useState([]);
useEffect(() => {
if (exam) {
setChipValue(exam.equipment.map((sub) => sub.id));
}
}, [exam]);
const handleChange = (e) => {
const {
target: { value },
} = e;
console.log(value);
setChipValue(typeof value === "string" ? value.split(",") : value);
};
return (
<Modal open={exam !== null} onClose={onClose}>
{exam && (
<Box sx={style}>
<Typography
component={"span"}
id="transition-modal-description"
sx={{ mt: 2 }}
>
<p>{exam.name}</p>
<FormControl sx={{ m: 1, width: 300 }}>
<InputLabel id="demo-multiple-chip-label">Chip</InputLabel>
<Select
multiple
value={chipValue}
// value={value}
onChange={handleChange}
input={<OutlinedInput id="select-multiple-chip" label="Chip" />}
renderValue={(selected) => {
return (
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 0.5 }}>
{selected.map((value) => {
const option = equipment.find((o) => o.id === value);
return <Chip key={value} label={option.name} />;
})}
</Box>
);
}}
MenuProps={MenuProps}
>
{equipment.map((option) => (
<MenuItem key={option.id} value={option.id}>
{option.name}
</MenuItem>
))}
</Select>
</FormControl>
</Typography>
</Box>
)}
</Modal>
);
}
See how much simple it gets when you split the logic. Here is the sandbox: https://codesandbox.io/s/hedk9g

How can i render a component but with multiples content

I have a card component generator, that grabs info from a const array and renders an div with the data in a sort of a table inside a card UI component.
I need to implement an ADD button inside of each card so i can open an modal with some inputs.
But, as the modal is inside the function, every modal on differen cards are rendering the same
how can i make an implementation so each modal grab something unique to the card being rendered ?
here's the code
function ProntCard() { const [modal, setModal] = useState(false);
const columns = [
{
title: "Estado de Saúde",
dataIndex: "1",
key: "name",
width: 150,
},
{
title: "Diagnostico",
dataIndex: "2",
key: "age",
width: 150,
},
{
title: "Medicação",
dataIndex: "3",
key: "address 1",
ellipsis: true,
},
{
title: "Data de atendimento",
dataIndex: "4",
key: "address 2",
ellipsis: true,
},
{
title: "Nota",
dataIndex: "",
key: "address 3",
ellipsis: true,
},
];
const nomes = [
{
nome: "Condições de Saúde / Comorbidades",
colunas: [
{
title: "Estado de Saúde",
dataIndex: "name",
key: "name",
width: 150,
},
{
title: "Sintomas",
dataIndex: "age",
key: "age",
width: 150,
},
{
title: "Diagnóstico",
dataIndex: "date",
key: "address 1",
ellipsis: true,
},
{
title: "Data de atendimento",
dataIndex: "address",
key: "address 2",
ellipsis: true,
},
{
title: "Nota",
dataIndex: "tags",
key: "address 3",
ellipsis: true,
},
],
laudos: [
{
key: "1",
name: "Atípico",
age: "Leve dor de cabeça",
date: "Dipirona de 1g",
address: "02/01/2021",
tags: "Noite de Sono mal dormida",
},
{
key: "2",
name: "Convencional",
age: "Leve dor membros",
date: "Insulina de 1g",
address: "02/01/2021",
tags: "Mal estar",
},
],
},
function showModal() {
setModal(!modal);
}
function CardsHost(props) {
const cards = nomes.map((nome) => (
<div>
<div className="box2">
<div className="box2header">
<div>
<h3>{nome.nome}</h3>
</div>
<div className="addSpan">
<PlusCircleOutlined />
<span onClick={showModal}> Adicionar</span>
</div>
</div>
<div className="box2info">
<Table columns={nome.colunas} dataSource={nome.laudos} />
</div>
</div>
</div>
));
return <div className="controler">{cards}</div>;
}
return (
<>
<div className="">
<CardsHost posts={nomes} />
</div>
<Modal
visible={modal}
onOk={showModal}
title="Novo Prontuário"
onCancel={showModal}
width={1000}
>
{columns.map((column) => (
<div key={column.key} className="labelll">
<label>{column.title}</label>
<Input style={{ width: "61.3%" }} />
</div>
))}
</Modal>
</>
);
}
export default ProntCard;
If what you really want is pass specific data to the modal based on the Card you select, change this part.
<span onClick={showModal}> Adicionar</span>
As follow.
<span onClick={() => {showModal(nome)}}> Adicionar</span>
Customize showModal function to set necessary data as a state.
If I understood the question correctly, you can render different jsx for each different card:
const cards = nomes.map((name, index) => (
<UniqueCard key={index} name={name} />
));
UniquCard.jsx:
export const UniqueCard = ({key, name}) => {
const renderCard = () => {
switch(name){
case 'name1':
return <p style={{color: 'red'}}> Card name: {name} </p>
case 'name2':
return <p style={{color: 'yellow'}}> Card name: {name} </p>
case 'name3':
return <p style={{color: 'green'}}> Card name: {name} </p>
default:
return <p> No card </p>
}
}
return (
<> {renderCard()} </>
)
}
Use the index of the map-loop:
function showModal(index) {
// use the index here to find element in array
}
const cards = nomes.map((nome, index) => (
<span onClick={() => showModal(index)}> Adicionar</span>
))
You can assign this index to any property you want to use it later to uniquely identify each modal.

Material UI react autocomplete set different label and different value

we can see the example here at https://material-ui.com/components/autocomplete/
I wanted to set option label and value different.
Like here is example used
const defaultProps = {
options: top5Films,
getOptionLabel: (option) => option.title,
};
<Autocomplete
{...defaultProps}
id="auto-complete"
value={value}
onChange={(event, newValue) => {
setValue(newValue);
}}
autoComplete
includeInputInList
renderInput={(params) => <TextField {...params} label="clearOnEscape" margin="normal"/>}
/>
const top5Films= [
{ title: 'The Shawshank Redemption', year: 1994 },
{ title: 'The Godfather', year: 1972 },
{ title: 'The Godfather: Part II', year: 1974 },
{ title: 'The Dark Knight', year: 2008 },
{ title: '12 Angry Men', year: 1957 }
]
But I have data like:
const top5Films= [
{ id: 1, title: 'The Shawshank Redemption', year: 1994 },
{ id: 2, title: 'The Godfather', year: 1972 },
{ id: 3, title: 'The Godfather: Part II', year: 1974 },
{ id: 4, title: 'The Dark Knight', year: 2008 },
{ id: 5, title: '12 Angry Men', year: 1957 }
]
I want to set id as value and show title as label.
Looks like the object is assigned to the value.
So setting id to value crashed the options.
I used the id from the object in following way for further operation.
/* eslint-disable no-use-before-define */
import React from "react";
import TextField from "#material-ui/core/TextField";
import Autocomplete from "#material-ui/lab/Autocomplete";
export default function Playground() {
const [value, setValue] = React.useState(null);
const [id, setId] = React.useState(null);
const [title, setTitle] = React.useState(null);
return (
<div>
<div>{`value: ${value}`}</div>
<div>{`id: ${id}`}</div>
<div>{`title: ${title}`}</div>
<br />
<div style={{ width: 300 }}>
<Autocomplete
options={top5Films}
getOptionLabel={option => option.title}
id="movies"
value={value}
onChange={(event, newValue) => {
console.log(newValue);
if (newValue) {
setValue(newValue);
setId(newValue.id);
setTitle(newValue.title);
}
}}
renderInput={params => (
<TextField {...params} label="Movies" margin="normal" />
)}
/>
</div>
</div>
);
}
// Top 5 films as rated by IMDb users. http://www.imdb.com/chart/top
const top5Films = [
{ id: 1, title: "The Shawshank Redemption", year: 1994 },
{ id: 2, title: "The Godfather", year: 1972 },
{ id: 3, title: "The Godfather: Part II", year: 1974 },
{ id: 4, title: "The Dark Knight", year: 2008 },
{ id: 5, title: "12 Angry Men", year: 1957 }
];
This works for now but best answer is always welcome.
I couldn't fully understand your issue but I guess you want to have different display option for getOptionLabel and different display in the dropdown list. If that's the case, you can simply use renderOption provided by the Material UI. Check out an example here : https://codesandbox.io/s/94xlp?file=/demo.js
import React from "react";
import { TextField } from "#material-ui/core";
import { Autocomplete } from "#material-ui/lab";
return (
<Autocomplete
freeSolo
name=""
options={top5Films }
getOptionLabel={(option) => option.title} //Displays title only in input field
renderOption={(option) => (
<React.Fragment>
{option.title + "," + " " + option.year} //Displays title + year in dropdown list
</React.Fragment>
)}
renderInput={params => (
<Field
component={FormikTextField}
{...params}
label=""
name=""
/>
)}
/>
);
}
Try this, set a json value and use the name for inputValue, the input value not change why not calling onChange function
<Autocomplete
options={machineList}
inputValue={formValues.machine.name || ""} // from formik context in my case
onChange={(e, value) => {
setValues(
"machine",
value && value.id ? { id: value.id, name: value.name } : "" //use json value
);
}}
getOptionLabel={(option) => option.name}
renderInput={(params) => (
<InputField
{...params}
type="text"
name={machine.name}
label={machine.label}
fullWidth
/>
)}
/>;
okk you can try in this way -
const options = [
{
id: 212,
label: 'First Title'
},
{
id: 321,
label: 'Second Title'
},
{
id: 543,
label: 'Third Title'
}
]
<Autocomplete
placeholder="Search…"
options={options}
isOptionEqualToValue={(option, value) => option.id === value.id}
renderInput={(params) => <TextField {...params} label={'label'} />}
renderOption={(props, option) => {
return (
<li {...props}>
{option.label}
</li>
)
}}
onChange={(_event, value) => {
setValue(value.id)
}}
/>

Filling a model with a list from Textarea

Now I do not really understand you. Sorry, I just started this whole study not so long ago. I’ll try to explain again what I can’t do.
I have an empty object and an object with data with the same structure.
data: [
{id: 1, title: "title1"},
{id: 2, title: "title1"},
{id: 3, title: "title3"},
{id: 4, title: "title4"},
{id: 5, title: "title3"}
],
item: [
{
itemId: "",
itemname: ""
}
]
And I have select and textarear. Select have data, textarear empty. Textarear displays title.
I want to press a button. Selected item from select. copied to textarear (title only), and also itemId - this selected element id: 5 and itemname - the same title: "title3" element, was recorded in item [].
https://codesandbox.io/s/priceless-hermann-g9flw
Please do check now
import React from "react";
class App extends React.Component {
constructor() {
super();
this.state = {
id: null,
title: "",
filmItem: "",
listFilms: [],
data: [
{ id: 1, title: "title1" },
{ id: 2, title: "title2" },
{ id: 3, title: "title3" },
{ id: 4, title: "title4" }
],
item: []
};
this.onChange = this.onChange.bind(this);
this.onChangeArea = this.onChangeArea.bind(this);
this.addFilm = this.addFilm.bind(this);
this.choice = this.choice.bind(this);
}
addFilm(film) {
const selectedData = this.state.data.find(item => item.id == film);
console.log(selectedData);
this.setState({
listFilms: [...this.state.listFilms, selectedData.title],
item: [
...this.state.item,
{ itemId: selectedData.id, itemname: selectedData.title }
]
});
}
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
onChangeArea = e => {
this.setState({ [e.target.name]: e.target.value.split("\n") });
};
choice(title) {
this.setState({ filmItem: title });
}
render() {
return (
<div className="App">
<div className="row App-main">
<div>
<select name="filmItem" size="4" onChange={e => this.onChange(e)}>
{this.state.data.map(film => (
<option key={film.title} value={film.id}>
{film.title}
</option>
))}
</select>
</div>
<div>
<button
className="editButton"
onClick={() => this.addFilm(this.state.filmItem)}
>
button
</button>
</div>
<div>
<textarea
name="films"
onChange={this.onChangeArea}
value={this.state.listFilms.map(r => r).join("\n")}
/>
</div>
<div>
<input type="text" name="text-input" onChange={this.onChange} />
</div>
</div>
<pre style={{ whiteSpace: "pre-wrap" }}>
{JSON.stringify(this.state)}
</pre>
</div>
);
}
}
export default App;

Categories

Resources