Why is the map undefined? - javascript

I am a novice at redux and i am trying to incorporate it in my code so the state can be managed more easily. I am trying to map through an array in my state but it is throwing the error below:
Uncaught TypeError: Cannot read property 'map' of undefined
this is the reducer for redux
const initialState = {
workoutlist: [
{
id: uuid.v4(),
name: 'Leg Day',
date: '08-09-2019',
duration: "60",
exerciselist: [
{
id: uuid.v4(),
exerciseName: 'Squats',
numberOfSets: "3",
reps: "12",
weight: "135",
},
{
id: uuid.v4(),
exerciseName: 'Leg press',
numberOfSets: "3",
reps: "10",
weight: "150",
},
{
id: uuid.v4(),
exerciseName: 'Lunges',
numberOfSets: "4",
reps: "12",
weight: "0",
},
],
selected: false,
},
{
id: uuid.v4(),
name: 'Running',
date: '08-11-2019',
duration: "40",
exerciselist: [],
selected: false,
},
],
disabled: true,
page: 1,
}
const workoutList = (state = initialState, action) => {
switch(action.type) {
// Returns whether the panel is selected or not
// and enables Start Workout button if only 1 is selected
case 'SELECT_PANEL':
state = {
workoutlist: state.workoutlist.map(workout => {
if (workout.id === action.id) {
workout.selected = !workout.selected
}
return workout;
})
}
var count = 0;
state.workoutlist.map((workout) => {
if (workout.selected === true) {
count = count + 1;
}
return count;
})
if (count !== 1) {
state = {
...state,
disabled: true
}
} else {
state = {
...state,
disabled: false
}
}
return state;
default:
return state;
}
}
this is the component that where the error is being thrown.
export default function WorkoutItem() {
const handleSelectedPanel = useSelector(state => state.workoutList);
const dispatch = useDispatch();
const { name, date, duration, exerciselist } = handleSelectedPanel;
return (
<ExpansionPanel style={styles.panel} onChange={() => dispatch(selectPanel())}>
<ExpansionPanelSummary>
<Typography variant="button" style={styles.header}>
{name}
</Typography>
<Typography variant="button" style={styles.header}>
{date}
</Typography>
<Typography align="right" style={styles.header}>
~{duration} mins
</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<Table size="medium" style={styles.table}>
<TableHead>
<TableRow>
<TableCell padding="none" >Name</TableCell>
<TableCell padding="none" align="right"># of sets</TableCell>
<TableCell padding="none" align="right">average reps</TableCell>
<TableCell padding="none" align="right">weight</TableCell>
</TableRow>
</TableHead>
<TableBody>
{exerciselist.map((exercise) => (
<ExerciseList
key={exercise.id}
exercise={exercise}
/>
))}
</TableBody>
</Table>
<ExpansionPanelActions disableSpacing style={styles.actionButton}>
<EditWorkoutItem
workout={this.props.workout}
handleEditChange={this.props.handleEditChange}
/>
</ExpansionPanelActions>
</ExpansionPanelDetails>
</ExpansionPanel>
)
}
It is supposed to show a list of panels that can be expanded to show the contents but it throws an error saying the exerciselist is undefined in my state apparently.
Any help would be greatly appreciated!

Do you want to access the first item or workoutList ?. From your code handleSelectedPanel seams to be an array not an object. Is your destructuring correct?. Where is your useSelector?. What does console.log(handleSelectedPanel) gives you? Try
const { name, date, duration, exerciselist } = handleSelectedPanel[0];
or
const handleSelectedPanel = useSelector(state => state.workoutList[0]);

Related

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 to use drag and drop in ant design?

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

Cannot Hook Category Name, and return the else statement

I made a function getCategoryNameById to get and match the id of the product and I pass the function as props in the other component to use it but when it's render a else statement which is a "none" string.
Example Data
Product Dummy Data
{
id: 4,
name: "ByProgrammers Sushi",
rating: 4.9,
categories: [1],
priceRating: expensive,
photo: images.japanese_restaurant,
duration: "10 - 15 min",
location: {
latitude: 1.5578068150528928,
longitude: 110.35482523764315,
},
courier: {
avatar: images.avatar_4,
name: "Ahmad"
},
menu: [
{
menuId: 9,
name: "Sushi sets",
photo: images.sushi,
description: "Fresh salmon, sushi rice, fresh juicy avocado",
calories: 100,
price: 50
}
]
},
Dummy Category Data
const categoryData = [
{
id: 1,
name: "Rice",
icon: icons.rice_bowl,
},
The State
const [categories, setCategories] = useState(categoryData)
const [selectedCategory, setSelectedCategory] = useState(null)
const [restaurants, setRestaurants] = useState(restaurantData)
const [currentLocation, setCurrentLocation] = useState(initialCurrentLocation)
The Function
function getCategoryNameById(id) {
let category = categories.filter(a => a.id == id)
if(category.length > 0)
return category[0].name
return "none"
}
Home Component
return (
<HomeComponentContext.Provider value={{
selectedCategory
}}>
<SafeAreaView>
<Top name={currentLocation.streetName}/>
<Categories
item={categories}
funct={onSelectedCategory}
selectcat={selectedCategory}
/>
<Product
products={restaurants}
function={getCategoryNameById}
cate = {categories}
/>
</SafeAreaView>
</HomeComponentContext.Provider>
)
the Usage of the Function in the Product Component
{
props.cate.map((categoryId) => {
return(
<View
key={categoryId}
style={{
flexDirection:'row'
}}
>
<Text style={{ ...FONTS.body3 }}>
{props.function(categoryId)}
</Text>
<Text>.</Text>
</View>
)
})
}

React change parent array properties

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)
// ...
}

How to upload data to server from dynamic UI in react native

Here in this code I am getting some array value, which is dynamic. On basis of that value I am generating UI. This value may change so according to that UI will change.
Now I have to upload all data on button click to server, I am getting confused.
Like if we have 3 fields static, I can create 3 states and by using that I can pass that value to the API.
But here as I am generating dynamic UI how can I take value and upload.
Below is the array value on basis of that I am generating dynamic form.
formFields: Array(8)
0:
key: "dateOfBirth"
label: "Date of Birth"
model: "model.dateOfBirth"
name: "dateOfBirth"
placeHolder: "DD/MM/YYYY"
position: "1"
required: "true"
type: "date"
__typename: "FormFields"
__proto__: Object
1:
key: "lastRechargedAmount"
label: "Last RCC Amt."
model: "model.lastRechargedAmount"
name: "lastRechargedAmount"
placeHolder: "Amount in Naira"
position: "2"
required: "false"
type: "text"
__typename: "FormFields"
__proto__: Object
2:
key: "stateOfOrigin"
label: "State of Origin"
model: "model.stateOfOrigin"
name: "stateOfOrigin"
placeHolder: "State of origin"
position: "3"
required: "true"
type: "parentSelect"
__typename: "FormFields"
__proto__: Object
3: {type: "childSelect", model: "model.lgaOfOrigin", label: "LGA of Origin", placeHolder: "Enter Lga of origin", key: "lgaOfOrigin", …}
4:
key: "frequentlyDialledNumbers1"
label: "Freq.Dialled No"
model: "model.frequentlyDialledNumbers"
name: "frequentlyDialledNumbers1"
placeHolder: "frequently dialled MSISDN"
position: "5"
required: "true"
type: "text"
__typename: "FormFields"
__proto__: Object
5: {type: "text", model: "model.frequentlyDialledNumbers", label: "Freq.Dialled No", placeHolder: "frequently dialled MSISDN", key: "frequentlyDialledNumbers2", …}
6: {type: "text", model: "model.frequentlyDialledNumbers", label: "Freq.Dialled No", placeHolder: "frequently dialled MSISDN", key: "frequentlyDialledNumbers3", …}
7: {type: "text", model: "model.frequentlyDialledNumbers", label: "Freq.Dialled No", placeHolder: "frequently dialled MSISDN", key: "frequentlyDialledNumbers4", …}
length: 8
The code below I am using to generate UI and on button press I am calling function validatUser(). On button press I have to take all values and send in this function.
class CustomerEvalidation extends Component {
constructor(props) {
super(props);
const { eValidationMasterData } = this.props;
this.state = {
selectedRow: -1,
disableBtn: true,
showSimSwapReason: false,
dateOfBirth: currentDate,
lastName: '',
lgaValue: eValidationMasterData.masterData.lga[0].code,
stateValue: eValidationMasterData.masterData.lga[0].state.name,
stateCode: eValidationMasterData.masterData.lga[0].state.code,
isModalVisible:false
};
}
componentWillUnmount() {
this.setState({
showSimSwapReason: false
});
}
lgaChanged = (key, val) => {
this.handleChangeLga({ field: "lgaValue" }, val);
};
handleChangeLga = (props, e) => {
const { lga } = this.props.eValidationMasterData.masterData;
let tempObj = this.state.lgaValue;
for (let i = 0; lga[i]; i++) {
if (lga[i].code == e) {
const stateData = lga[i].state;
this.setState({
stateValue: stateData.name,
stateCode: stateData.code
})
}
}
tempObj[props.field] = e;
this.setState({ lgaValue: e });
};
validatUser = () => {
const {dateOfBirth,lgaValue,stateCode}=this.state;
const validateUser = {
dateOfBirth: dateOfBirth,
lgaValue:lgaValue,
stateCode:stateCode
}
this.props.verifySecurityQuestions(validateUser);
}
onChangeExp = (e) => {
this.setState({
dateOfBirth: e
})
}
render() {
const { dateOfBirth, lastName, lgaValue, stateValue } = this.state;
const { isCamera, loading, error, securityQuestions, eValidationMasterData,validateUser } = this.props;
const { formFields } = securityQuestions.evalidatorType[0].SelectionList[0];
const { lga } = eValidationMasterData.masterData;
let lgaOptions = [];
lga.map(({ code: value, name: label }) => {
lgaOptions.push({ value, label });
});
return (
<View style={{minHeight: deviceHeight, color:'#fff'}}>
{loading &&
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<OverlaySpinner color="#00678F" />
</View>}
{!isCamera && (
<View style={styles.container}>
{formFields.map((document, index) => {
return (
<View style={{backgroundColor: '#fff' }}
key={index}>
{document.type === 'text' && (
<View style={{ padding: 15}} >
<View style={{ flexDirection: 'row', backgroundColor: '#fff' }}>
<SmallText textColor="grey" text={document.label} />
</View>
<Item style={{ borderColor: '#00fff', borderBottomWidth: 1, marginLeft: 0 }}>
<Input
value={lastName}
keyboardType='default'
onChangeText={(lastName) =>
this.setState({ lastName: lastName.replace(/\s/g, '') })}
/>
</Item>
</View>
)
}
{document.type === 'date' && (
<View style={{ padding: 15}}>
<View style={{
flexDirection: 'row', backgroundColor: '#fff'
}}>
<SmallText textColor="grey" text={document.label} />
</View>
<Item style={{ borderColor: '#00fff', borderBottomWidth: 1, marginLeft: 0 }}>
<DatePicker
minDate={minDate}
maxDate={currentDate}
currentDate={dateOfBirth}
format={format}
width={deviceWidth}
onChange={(dateOfBirth) => this.onChangeExp(dateOfBirth)}
marginLeft={0}
/>
</Item>
</View>
)}
</View>
);
}
)}
</View>
)}
<View style={{ flexDirection: 'column', padding: 15 }}>
<View style={{ flexDirection: 'column', flex:1 }}>
<SelectField options={lgaOptions} value={lgaValue}
onChange={this.lgaChanged} that={this}
label={"LGA of Origin"} />
</View>
<View style={{ flexDirection: 'column' }}>
<View style={{ flexDirection: 'row', backgroundColor: '#fff' }}>
<SmallText textColor="grey" text={"State of Origin"} />
</View>
<Item style={{ borderColor: '#00fff', borderBottomWidth: 1, marginLeft: 0 }}>
<Input
value={stateValue}
keyboardType='default'
onChangeText={(stateValue) =>
this.setState({ stateValue: stateValue.replace(/\s/g, '') })}
/>
</Item>
</View>
<View style={{ paddingBottom: 15, marginTop: 20 }}>
<PrimaryBtn label={'Validate User'} disabled={false}
onPress={() => this.validatUser()} />
</View>
</View>
</View>
);
}
}
export default CustomerEvalidation;
Please check my SupplierForm example hope you will get a lots of information
Constant data
"formFields": [{
"id": "1",
"name": "companyname",
"label": "Company name",
"type": "input",
"placeholder": "",
"returnKeyType": "go"
},
{
"id": "2",
"name": "supplier_type",
"label": "Supplier type",
"type": "drop_down"
},
{
"id": "3",
"name": "country",
"label": "Country",
"type": "drop_down"
},
{
"id": "4",
"name": "phonenumber",
"label": "Mobile number",
"type": "input",
"placeholder": "",
"returnKeyType": "next"
},
{
"id": "5",
"name": "phonenumber1",
"label": "Landline number",
"type": "input",
"placeholder": "",
"returnKeyType": "next"
},
{
"id": "6",
"name": "email",
"label": "Email / UserID",
"type": "input",
"placeholder": "",
"returnKeyType": "next"
},
{
"id": "7",
"name": "contact_person",
"label": "Contact person",
"type": "input",
"placeholder": "",
"returnKeyType": "next"
},
{
"id": "8",
"name": "skype_id",
"label": "Skype id",
"type": "input",
"placeholder": "",
"returnKeyType": "next"
},
{
"id": "9",
"name": "notes",
"label": "Notes",
"type": "input",
"placeholder": "",
"returnKeyType": "go"
}
]
SupplierForm component
// #flow
import * as React from 'react';
import { Div, Button, InputText, DropDown } from '../../materialComponents';
import data from '../../constantData/supplier';
/* flow types
============================================================================= */
type Props = {
action: string,
editData?: ?{
companyname: string,
supplier_type_id: number | string,
country: number | string,
phonenumber: string,
phonenumber1: string,
landlord_email: string,
contact_person: string,
landlord_skype_id: string,
notes: string,
},
data: Object,
buttonLoader: boolean,
onSubmit: (data: Object) => any,
onError: (type: string, msg: string) => any,
};
type State = {
companyname: string,
supplier_type_id: number | string,
country_id: number | string,
phonenumber: string,
phonenumber1: string,
email: string,
contact_person: string,
skype_id: string,
notes: string,
};
/* ============================================================================
<SupplierForm />
============================================================================= */
class SupplierForm extends React.Component<Props, State> {
static defaultProps = { editData: null };
constructor() {
super();
this.state = {
companyname: '',
supplier_type_id: 0,
country_id: 0,
phonenumber: '',
phonenumber1: '',
email: '',
contact_person: '',
skype_id: '',
notes: '',
};
}
componentDidMount() {
const { editData, action } = this.props;
if (action === 'edit') {
const record = { ...editData };
const {
companyname,
supplier_type_id,
country,
phonenumber,
phonenumber1,
landlord_email,
contact_person,
landlord_skype_id,
notes,
} = record;
this.setState({
companyname,
supplier_type_id,
country_id: country,
phonenumber,
phonenumber1,
email: landlord_email,
contact_person,
skype_id: landlord_skype_id,
notes,
});
}
}
// for submit form
_handleSubmit = () => {
const { onError, onSubmit } = this.props;
const {
companyname,
supplier_type_id,
country_id,
phonenumber,
phonenumber1,
email,
contact_person,
skype_id,
notes,
} = this.state;
const supplier = {
companyname,
supplier_type_id,
country_id,
phonenumber,
phonenumber1,
email,
contact_person,
skype_id,
notes,
};
if (!companyname) {
onError('error', 'Please Enter Company Name');
} else if (!Number(supplier_type_id)) {
onError('error', 'Please Select Supplier Type');
} else if (!Number(supplier_type_id)) {
onError('error', 'Please Select Country');
} else if (!email) {
onError('error', 'Please Enter Email');
} else {
onSubmit(supplier);
}
};
/**
* handle picker values
* #param {string} fieldName
* #param {string} value
*/
_handlePickerValue = (pickerName: string, _id: string) => {
this.setState({
[`${pickerName}_id`]: _id,
});
};
/**
* handle input values
* #param {string} fieldName
* #param {string} value
*/
_handleInputValue = (fieldName: string, value: string) => {
this.setState({ [fieldName]: value });
};
/**
* render the all input fields
* #param {Object} dropDownData
*/
_renderInputFields = (dropDownData: Object) => {
const { formFields } = data;
return formFields.map(field => {
if (field.type === 'input') {
return (
<InputText
key={field.id}
label={field.label}
value={this.state[field.name]}
onChangeText={value => this._handleInputValue(field.name, value)}
reference={input => {
// $FlowFixMe
this[`${field.name}_ref`] = input;
}}
returnKeyType={field.returnKeyType}
// $FlowFixMe
onSubmitEditing={() => this[`${field.name}_ref`].focus()}
/>
);
}
if (field.type === 'drop_down') {
const itemData =
field.name === 'country'
? dropDownData.countries
: dropDownData[`${field.name}s`];
const selectedValue = this.state[`${field.name}_id`];
return (
<DropDown
key={field.id}
label={field.label}
data={itemData}
selectedValue={selectedValue}
onChange={value => this._handlePickerValue(field.name, value)}
/>
);
}
return null;
});
};
render() {
const { data: dropDownData, buttonLoader, action } = this.props;
const buttonTitle = action === 'add' ? 'Save' : 'Update';
return (
<Div>
{this._renderInputFields(dropDownData)}
<Button
loader={buttonLoader}
color="#FFFFFF"
backgroundColor="#21A24F"
marginVertical={10}
borderRadius={2}
iconName="save"
title={buttonTitle}
onPress={this._handleSubmit}
/>
</Div>
);
}
}
/* export
============================================================================= */
export default SupplierForm;
sorry, i'm a lazy coder .... i'll try to answer AbriefAP . . .
state is not the only option to hold variables, use/create object and push values there;
var obj1={};
_on_fld_change(document,v){
obj1[document.name]=v;
}
_on_submit(){
return fetch(URL,'POST',{obj1})
}
render(){
...
return(
..
<Comp onValueChange={(v)=>this._on_fld_change(document,v)}/>
)
}

Categories

Resources