extract object items in object array at react template - javascript

I'm newbies in react and javascript. I try to use this below data in react template. They're object array so i want to every items in this object array print separately in HTML (react template). Anyone can help me, i have code below, please help:
const fakeData = [
{
MOP: 'MOP',
code: '#1180-xxxx',
date: '10-08-2018',
status: 'Pending Order',
},
{
MOP: 'MOP1',
code: '#1180-xxxx1',
date: '11-08-2018',
status: 'Pending Order',
},
{
MOP: 'MOP2',
code: '#1180-xxxx2',
date: '12-08-2018',
status: 'Pending Order',
},
];
export class TransactionPage extends React.PureComponent {
constructor(props) {
super(props);
this.state = { fakeData };
}
render() {
const { classes, intl } = this.props;
return (
<Page>
<Helmet>
<title>{intl.formatMessage({ ...messages.header })}</title>
<meta
name="description"
content={<FormattedMessage {...messages.meta} />}
/>
</Helmet>
<PageContent>
<Paper>
<Grid container>
<Grid item xs={12} sm={5} md={4} lg={3}>
<List className={classes.list} disablePadding>
// show the item here
</List>
</Grid>
<Hidden xsDown>
<Grid item sm={7} md={8} lg={9}>
<Grid
container
direction="column"
spacing={16}
className={classes.details}
>
<Grid item xs={12} className={classes.center} />
<Grid item xs={12}>
<Typography variant="h6">CREDIT DEBIT</Typography>
</Grid>
<Grid item xs={12}>
<Divider />
</Grid>
<Grid item xs={12} />
</Grid>
</Grid>
</Hidden>
</Grid>
</Paper>
</PageContent>
</Page>
);
}
}
TransactionPage.propTypes = {
intl: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
};
const mapStateToProps = createStructuredSelector({
TransactionPage: makeSelectTransactionPage(),
});
function mapDispatchToProps(dispatch) {
return {
dispatch,
};
}
const withConnect = connect(
mapStateToProps,
mapDispatchToProps,
);
const withReducer = injectReducer({ key: 'TransactionPage', reducer });
const withSaga = injectSaga({ key: 'TransactionPage', saga });
export default compose(
withStyles(styles),
injectIntl,
withReducer,
withSaga,
withConnect,
)(TransactionPage);
I want this code transform as output below in the page:
<Grid container>
<Grid item xs={12} sm={5} md={4} lg={3}>
<List className={classes.list} disablePadding>
<ListItem button>
<span>MOP</span>
<span>#1180-xxxx</span>
<span>10-08-2018</span>
<span>Pending Order</span>
<ListItemSecondaryAction>
<ArrowIcon />
</ListItemSecondaryAction>
</ListItem>
<ListItem button>
<span>MOP1</span>
<span>#1180-xxxx1</span>
<span>11-08-2018</span>
<span>Pending Order</span>
<ListItemSecondaryAction>
<ArrowIcon />
</ListItemSecondaryAction>
</ListItem>
<ListItem button>
<span>MOP2</span>
<span>#1180-xxxx2</span>
<span>12-08-2018</span>
<span>Pending Order</span>
<ListItemSecondaryAction>
<ArrowIcon />
</ListItemSecondaryAction>
</ListItem>
</List>
</Grid>
i'm using react, how to loop them in react template.

You just create a map with JSX:
<List className={classes.list} disablePadding>
{fakeData.map((item, i) => <ListItem key={item.MOP+"_" + i} button>....</ListItem>) }
</List>

You can map it like this pseudo...
var formatted = fakeData.map((item, idx) => {
return(
<ListItem key={idx}>
<span>{item.MOP}</span>
<span>{item.code}</span>
<span>{item.date}</span>
<span>{item.status}</span>
</ListItem>
)
})
return(
<List>
{formatted}
</List>
)

Related

How to show list items after state changes in react-redux

I have a menu bar that shows category of my shop. When I click on a category a product list of that category should be shown on my shop component (also I use redux library). It works correctly for first time, but when I click on another category the state changes and the filter products update too but they don't show on my shop component. I must click a button on page to show updated list in shop component. How can I show them immediately after updating?
App.jsx
<Menubar/>
<Routes>
<Route path='/shopping' element={<Shop />}></Route>
</Routes>
Menubar.jsx
export default function MenuBar() {
const products = useSelector(state=>state.products);
const navigate = useNavigate();
const getCategory = (e) => {
let category = e.target.innerText;
dispatch(filterProByCategory(products, category));
navigate('/shopping');
}
return (
<>
<ul>
<li onClick={(e)=>getCategory(e)}>
Fashion
</li>
</ul>
</>
)
}
Shop.jsx
export default function Shop() {
const products = useSelector(state => state.filters.filterProducts);
const [filterProducts, setFilterproducts] = useState(products);
return (
<>
<Grid item xs={12} md={8} dir='rtl'>
<Card sx={{ minWidth: 275 }}>
<CardContent>
{/* */}
<Grid container spacing={1}>
{filterProducts && filterProducts.map((product, index) => (
<Grid item xs={12} md={4}>
<ProductCard product={product} key={index} />
</Grid>
))}
</Grid>
</>
)
}
Just use the direct result of products instead of using it for creating another state variable filteredProducts with useState
export default function Shop() {
const products = useSelector(state=>state.filters.filterProducts);
// const [filterProducts , setFilterproducts] = useState (products);
return (
<>
<Grid item xs={12} md={8} dir='rtl'>
<Card sx={{ minWidth: 275 }}>
<CardContent>
{/* */}
<Grid container spacing={1}>
{products && products.map((product , index)=>(
<Grid item xs={12} md={4}>
<ProductCard product={product} key={index}/>
</Grid>
))}
</Grid>
</>
)
}

How to send/receive props to BasicLayout (#devexpress/dx-react-scheduler)

I'm from Angular and new to React. Im doing well but here is a problem I'm stuck at. As you can see I have BasicLayout and AppointmentForm, both are in one file. BasicLayout is being used inside AppointmentForm but not like an element i.e <BasicLayout/> so I'm not able to understand how to pass props or its even possible now. I want to trigger commitChanges(inside AppointmentForm) function when onSubmit(inside Basic Layout) function is triggered. How can I pass props between these components?
const BasicLayout = (props) => {
const formik = useFormik({
initialValues: {
title: '',
agenda: '',
description: '',
participants: [],
host: user?.id,
guest: '',
location: '',
},
validationSchema,
onSubmit: async (values) => {
values.startDate = props.appointmentData.startDate;
values.endDate = props.appointmentData.endDate;
values.guest = values.guest?._id;
createAppointment(values);
console.log(values);
},
});
return (
<Container>
<Typography sx={{ fontSize: 24, fontWeight: 'bold' }} color="text.primary" gutterBottom>
Create Appointment
</Typography>
<Box sx={{ flexGrow: 1 }}>
<FormikProvider value={formik}>
<Form autoComplete="off" onSubmit={handleSubmit}>
<Grid container spacing={2}>
<Grid item xs={6} md={6}>
<TextField
label="Title"
color="secondary"
id="title"
type="text"
key="title"
value={formik.values.title}
onChange={formik.handleChange}
{...getFieldProps('title')}
error={Boolean(touched.title && errors.title)}
helperText={touched.title && errors.title}
fullWidth
/>
</Grid>
<Grid item container xs={12} md={12} direction="row" justifyContent="center" alignItems="center">
<LoadingButton size="medium" type="submit" variant="contained" loading={isSubmitting}>
Create
</LoadingButton>
</Grid>
</Grid>
</Form>
</FormikProvider>
</Box>
<ToastContainer />
</Container>
);
};
const AppointmentsDashboard = (props) => {
const commitChanges = ({ added, changed, deleted }) => {
console.log(props);
console.log({ added, changed, deleted });
if (added) {
if (!isValidate) {
notify('Please fill all required fields', 'error');
return;
}
const startingAddedId = data.length > 0 ? data[data.length - 1].id + 1 : 0;
setData([...data, { id: startingAddedId, ...added }]);
}
if (changed) {
setData(
data.map((appointment) =>
changed[appointment.id] ? { ...appointment, ...changed[appointment.id] } : appointment
)
);
}
if (deleted !== undefined) {
setData(data.filter((appointment) => appointment.id !== deleted));
}
return data;
};
return (
<>
<Paper>
<Scheduler data={data} height={660}>
<ViewState currentDate={currentDate} />
<EditingState
onCommitChanges={commitChanges}
addedAppointment={addedAppointment}
onAddedAppointmentChange={changeAddedAppointment}
appointmentChanges={appointmentChanges}
onAppointmentChangesChange={changeAppointmentChanges}
editingAppointment={editingAppointment}
onEditingAppointmentChange={changeEditingAppointment}
onAppointmentFormClosing={() => {
console.log('asdasd');
}}
allowAdding={true}
/>
<WeekView startDayHour={9} endDayHour={17} />
<AllDayPanel />
<EditRecurrenceMenu />
<ConfirmationDialog />
<Appointments />
<AppointmentTooltip showOpenButton showDeleteButton />
<AppointmentForm basicLayoutComponent={BasicLayout} />
</Scheduler>
</Paper>
</>
);
};
export default AppointmentsDashboard;

Multiple buttons triggering the same modal component

I have an videos array, which in turn has objects of type Video (typing below).
I need that when clicking on the button corresponding to a specific video, I can open only one modal with the information of the clicked video.
interface VideosInfo {
id: number;
title: string;
url: string;
quiz: boolean;
}
interface PagePros {
videos: VideosInfo[]
}
Below is the component that renders the array of videos through a map, notice that inside the map, I have an onClick function that calls the modal.
import { VideoModal } from '../index';
import { useVideos } from '../../../../hooks/Videos';
export const Videos: React.FC<VideoProps> = ({ module_id }) => {
const [modalOpen, setModalOpen] = useState<boolean>(false);
const { getVideos, videos, loadingVideos } = useVideos();
const handleCloseModal = () => {
setModalOpen(false);
};
const VideosData = () => {
if (videos.length) {
return (
<List dense>
{videos?.map(video => (
<div key={video.id}>
<ListItem onClick={() => setModalOpen(true)} button>
<ListItemText primary={video.title} />
</ListItem>
<Divider />
<VideoModal
open={modalOpen}
handleClose={() => handleCloseModal()}
video={video}
video_id={video.id}
/>
</div>
))}
</List>
);
}
if (!videos.length && !loadingVideos) {
return (
<Typography variant="body1">
Não existem vídeos cadastrados neste módulo.
</Typography>
);
}
return <LoadingScreen text="Carregando vídeos..." />;
};
useEffect(() => {
getVideos(module_id);
}, [module_id, getVideos]);
return (
<Grid container spacing={2}>
<Grid item xs={12} md={12}>
<VideosData />
</Grid>
<Grid item xs={12} md={12}>
<Button variant="text" color="primary">
Novo Vídeo
</Button>
</Grid>
</Grid>
);
};
And below the VideoModal component:
export const VideoModal: React.FC<ModalProps> = ({
video,
open,
handleClose,
video_id,
}) => {
console.log('videos modal', video);
return (
<Dialog
open={open}
aria-labelledby="form-dialog-title"
onClose={handleClose}
>
<DialogTitle id="form-dialog-title">Subscribe</DialogTitle>
<DialogContent>
<h2>test</h2>
</DialogContent>
</Dialog>
);
};
I understand that the modal uses the "open" property to define whether it is open or not, but when I click the button and perform the setModalOpen, it renders a modal for each object in the array. I don't understand how I could assemble this correctly.
I solved it as follows, created a state called videoToModal of type VideosInfo and a function called handleModalOpen, passed the video parameter to the function, and in the function stored this video in the videoToModal state.
I instantiated the VideoModal component outside the map (obviously should have done this before) and passed the state to the VideoModal component's video parameter.
Below is the complete code for the component.
import React, { useEffect, useState } from 'react';
import {
Button,
Divider,
Grid,
IconButton,
List,
ListItem,
ListItemSecondaryAction,
ListItemText,
Tooltip,
Typography,
} from '#material-ui/core';
import { Delete, QuestionAnswer } from '#material-ui/icons';
import { useVideos } from '../../../../hooks/Videos';
import { useStyles } from './styles';
import { LoadingScreen } from '../../../../components/CustomizedComponents';
import { VideoModal } from '../index';
import { VideosInfo } from '../../../../hooks/Videos/types';
import { VideoProps } from './types';
export const Videos: React.FC<VideoProps> = ({ module_id }) => {
const [openModal, setOpenModal] = useState<boolean>(false);
const [videoToModal, setVideoToModal] = useState<VideosInfo>();
const classes = useStyles();
const { getVideos, videos, loadingVideos } = useVideos();
const handleCloseModal = () => {
setOpenModal(false);
};
const handleOpenModal = (video: VideosInfo) => {
setVideoToModal(video);
setOpenModal(true);
};
const VideosData = () => {
if (videos.length) {
return (
<List dense>
{videos?.map(video => (
<div key={video.id}>
<ListItem
className={classes.listItem}
onClick={() => handleOpenModal(video)}
button
>
<ListItemText
primary={video.title}
className={classes.listItemText}
/>
<ListItemSecondaryAction>
<Tooltip
placement="top"
title={
video.Quizzes?.length
? 'Clique para ver as perguntas'
: 'Clique para iniciar o cadastro de perguntas'
}
>
<IconButton edge="end" aria-label="delete">
<QuestionAnswer
color={video.Quizzes?.length ? 'primary' : 'action'}
/>
</IconButton>
</Tooltip>
<Tooltip placement="top" title="Deletar Vídeo">
<IconButton edge="end" aria-label="delete">
<Delete color="secondary" />
</IconButton>
</Tooltip>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</div>
))}
<VideoModal
open={openModal}
handleClose={() => handleCloseModal()}
video={videoToModal}
/>
</List>
);
}
if (!videos.length && !loadingVideos) {
return (
<Typography variant="body1">
Não existem vídeos cadastrados neste módulo.
</Typography>
);
}
return <LoadingScreen text="Carregando vídeos..." />;
};
useEffect(() => {
getVideos(module_id);
}, [module_id, getVideos]);
return (
<Grid container spacing={2} className={classes.container}>
<Grid item xs={12} md={12}>
<VideosData />
</Grid>
<Grid item xs={12} md={12}>
<Button variant="text" color="primary">
Novo Vídeo
</Button>
</Grid>
</Grid>
);
};
Instead of using
<div key={video.id}>
can you use,
<List dense>
{videos?.map((video,i) => (
<div key={i}>
<ListItem onClick={() => setModalOpen(true)} button>
<ListItemText primary={video.title} />
</ListItem>
<Divider />
<VideoModal
open={modalOpen}
handleClose={() => handleCloseModal()}
video={video}
video_id={video.id}
/>
</div>
))}
</List>

passing props for components to useMemo getting undefine

I am passing data in the MemoDownloadsSubTab component but when I am trying to use it in MemoDownloadsSubTab in useMemo I am getting error data that is not defined I am not sure why this is happening let me know what I need to change so any another way I need to pass data in parent to child and us in the child component.
export const CorporateDetailsTable = ({
userHistorySummary,
}) => {
const MemoDownloadsSubTab = React.useMemo(
({ data = [] }) => {
return (
<>
{data?.length !== 0 &&
data?.map((row, rowIndex) => {
return (
<Box bgcolor="mainDetailsCard.primary" m={1} p={1} borderRadius={5}>
<Grid xs={12} item container spacing={2}>
<Grid item xs={12} sm={3}>
<Typography component="div">
<Box fontWeight="fontWeightBold" component="span" mr={1}>
SRN :
</Box>
{row.SRN}
</Typography>
</Grid>
<Grid item xs={12} sm={3}>
<Typography component="div">
<Box fontWeight="fontWeightBold" component="span" mr={1}>
Charge ID :
</Box>
{row.CHARGE_ID ? row.CHARGE_ID : "N/A"}
</Typography>
</Grid>
</Grid>
</Box>
);
})}
</>
);
}
,[userHistorySummary?.charges]);
return (
<>
{userHistorySummary?.masterData?.length !== 0 ? (
<Box mt={1}>
return (
<MemoDownloadsSubTab
data={userHistorySummary?.charges}
title={"Charges Registered"}
cells={chargesCells}
classes={classes}
/>
</Box>
) : (
<Typography variant="subtitle1" color="textSecondary">
No Data Available
</Typography>
)}
</>
);
};

Unable to get the input from a textfield in React

I'm trying to get the input from a text-field in react but it just doesn't work and I have no clue why. I have looked at a lot of different solutions but none of them seem to work.
I even tried to follow this https://reactjs.org/docs/refs-and-the-dom.html but I'm not understanding this correctly?
class Activity extends Component {
constructor(props) {
super(props);
this.newActivity = React.createRef();
}
callAPI() {
fetch("http://localhost:5000/activities", {
method: 'POST',
body: JSON.stringify({
newName: this.newActivity.current,
oldName: this.state.activity
}),
})
.then(function (response) {
return response.json()
});
}
state = {
activity: this.props.data.name
}
render() {
return (
<React.Fragment>
<Grid justify="center" container spacing={(2, 10)} aligncontent="center">
<Grid item xs={8} >
<Paper>
{/*Trying to get the input here so that I can put it into my POST request*/}
<TextField inputRef={el => this.newActivity = el} type="activity" id="standard-basic" label="Standard" defaultValue={this.state.activity} />
</Paper>
</Grid>
<Grid item xs={2}>
<Button onClick={this.callAPI} variant="contained" startIcon={<UpdateIcon />} style={buttonStyle} >Uppdatera</Button>
</Grid>
<Grid item xs={2}>
<Button variant="contained" startIcon={<DeleteIcon />} style={buttonStyle} >Ta Bort</Button>
</Grid>
</Grid>
</React.Fragment>
);
}
}
The error I get is
TypeError: Cannot read property 'newActivity' of undefined
You must initiate state values inside the constructor.
Also change this line as inputRef={this.newActivity} instead of inputRef={(el)=>this.newActivity =el}. Because you already create ref using createRef no need to create again.
class Activity extends Component {
constructor(props) {
super(props);
this.state = {
activity: this.props.data.name
}
this.callAPI = this.callAPI.bind(this);
this.newActivity = React.createRef();
}
callAPI() {
fetch("http://localhost:5000/activities", {
method: 'POST',
body: JSON.stringify({
newName: this.newActivity.current,
oldName: this.state.activity
}),
})
.then(function (response) {
return response.json()
});
}
render() {
return (
<React.Fragment>
<Grid justify="center" container spacing={(2, 10)} aligncontent="center">
<Grid item xs={8} >
<Paper>
{/*Trying to get the input here so that I can put it into my POST request*/}
<TextField inputRef={this.newActivity} type="activity" id="standard-basic" label="Standard" defaultValue={this.state.activity} />
</Paper>
</Grid>
<Grid item xs={2}>
<Button onClick={this.callAPI} variant="contained" startIcon={<UpdateIcon />} style={buttonStyle} >Uppdatera</Button>
</Grid>
<Grid item xs={2}>
<Button variant="contained" startIcon={<DeleteIcon />} style={buttonStyle} >Ta Bort</Button>
</Grid>
</Grid>
</React.Fragment>
);
}
TextField is a wrapper component.
You can pass the ref to the native input like this:
import React, { Component, createRef } from 'react';
import TextField from '#material-ui/core/TextField';
export default class App extends Component {
ref = createRef();
render() {
return (
<div className="App">
<TextField inputProps={{ ref: this.ref }} />
</div>
);
}
}

Categories

Resources