Unable to get the input from a textfield in React - javascript

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>
);
}
}

Related

saga fetch data after component rendered

hi sorry for my bad english.i am using react and redux.i dispatch getTags action in layout component.problem is after getData action called,getDataSuccess action called after my components rendered.so my data is null.
how i can be sure that data is fetched and render my components?
layout:
function DashboardLayout({
children,
showSideBar,
backgroundColor,
getTagsFromServer,
getCategoriesFromServer,
}) {
getTagsFromServer();
getCategoriesFromServer();
return (
<StyledDashbordLayout>
<NavBar />
<SideBarDrawer />
<Grid container className="container">
{showSideBar && (
<Grid item className="sidebar-section">
<SideBar />
</Grid>
)}
<Grid item className="content">
{children}
</Grid>
</Grid>
</StyledDashbordLayout>
);
}
DashboardLayout.propTypes = {
children: PropTypes.node.isRequired,
showSideBar: PropTypes.bool.isRequired,
backgroundColor: PropTypes.string,
getTagsFromServer: PropTypes.func,
getCategoriesFromServer: PropTypes.func,
};
function mapDispatchToProps(dispatch) {
return {
dispatch,
getTagsFromServer: () => dispatch(getTags()),
getCategoriesFromServer: () => dispatch(getCategories()),
};
}
const withConnect = connect(
null,
mapDispatchToProps,
);
export default compose(withConnect)(DashboardLayout);
saga:
import { call, put, takeLatest } from 'redux-saga/effects';
function* uploadVideo({ file }) {
try {
const { data } = yield call(uploadVideoApi, { file });
yield put(uploadFileSuccess(data));
} catch (err) {
yield put(uploadFileFail(err));
}
}
function* getTags() {
const { data } = yield call(getTagsApi);
console.log(data, 'app saga');
yield put(getTagsSuccess(data));
}
function* getCategories() {
const { data } = yield call(getTCategoriesApi);
yield put(getCategoriesSuccess(data));
}
// Individual exports for testing
export default function* appSaga() {
yield takeLatest(UPLOAD_VIDEO, uploadVideo);
yield takeLatest(GET_TAGS, getTags);
yield takeLatest(GET_CATEGORIES, getCategories);
}
this is my select box component which gets null data from store:
import React, { useState } from 'react';
function UploadFileInfo({ tags, categories }) {
return (
<Paper square className={classes.paper}>
<Tabs
onChange={handleChange}
aria-label="disabled tabs example"
classes={{ indicator: classes.indicator, root: classes.root }}
value={tab}
>
<Tab
label="مشخصات ویدیو"
classes={{
selected: classes.selected,
}}
/>
<Tab
label="تنظیمات پیشرفته"
classes={{
selected: classes.selected,
}}
/>
</Tabs>
{tab === 0 && (
<Grid container className={classes.info}>
<Grid item xs={12} sm={6} className={classes.formControl}>
<label htmlFor="title" className={classes.label}>
عنوان ویدیو
</label>
<input
id="title"
type="text"
className={classes.input}
onChange={e => setValue('title', e.target.value)}
defaultValue={data.title}
/>
</Grid>
<Grid item xs={12} sm={6} className={classes.formControl}>
<SelectBox
onChange={e => setValue('category', e.target.value)}
value={data.category}
label="دسته بندی"
options={converItems(categories)}
/>
</Grid>
<Grid item xs={12} className={classes.textAreaWrapper}>
<label htmlFor="info" className={classes.label}>
توضیحات
</label>
<TextField
id="info"
multiline
rows={4}
defaultValue={data.info}
variant="outlined"
classes={{ root: classes.textArea }}
onChange={e => setValue('info', e.target.value)}
/>
</Grid>
<Grid item xs={12} sm={6} className={classes.formControl}>
<SelectBox
onChange={e => {
if (e.target.value.length > 5) {
console.log('hi');
setError(
'tags',
'تعداد تگ ها نمی تواند بیشتر از پنج عدد باشد',
);
return;
}
setValue('tags', e.target.value);
}}
value={data.tags}
label="تگ ها"
options={converItems(tags)}
multiple
onDelete={id => deleteTagHandler(id)}
error={errors.tags}
/>
</Grid>
</Grid>
)}
{tab === 1 && 'دومی'}
<Dump data={data} />
</Paper>
);
}
const mapStateToProps = createStructuredSelector({
tags: makeSelectTags(),
categories: makeSelectCategories(),
});
const withConnect = connect(
mapStateToProps,
null,
);
export default compose(withConnect)(UploadFileInfo);
Question Summary
If I understand your question correctly, you are asking how to guard the passing of options, options={converItems(tags)}, in the SelectBox in UploadFileInfo against null or undefined values when the data hasn't been fetch yet.
Solutions
There are a few options for either guarding against null or undefined values.
Easiest is to provide a default fallback value for tags. Here I am making an assumption the tags are an array, but they can be anything, so please adjust to match your needs.
Inline when passed options={converItems(tags || []) or options={converItems(tags ?? [])
In the function signature function UploadFileInfo({ tags = [], categories })
As part of a fallback return value in makeSelectTags
Another common pattern is conditional rendering where null may be the initial redux state value, so you simply wait until it is not null to render your UI.
Early return null if no tags
function UploadFileInfo({ tags, categories }) {
if (!tags) return null;
return (
<Paper square className={classes.paper}>
...
Conditional render SelectBox
{tags ? (
<SelectBox
...
/>
) : null
}
Side Note about fetching data calls in DashboardLayout
When you place function invocations directly in the function body they will be invoked any time react decides to "render" the component to do any DOM diffing, etc..., pretty much any time DashboardLayout renders the data fetches are made, which could have unintended effects. For this reason, react functional component bodies are supposed to be pure functions without side effects. Place any data fetching calls in an effect hook that is called only once when the component mounts (or appropriate dependency if it needs to be called under other specific conditions).
useEffect(() => {
getTagsFromServer();
getCategoriesFromServer();
}, []);
Use your functions to call the API inside React.useEffect.
All your API calls should be inside the useEffect hook.
For more on useEffect, read this
function DashboardLayout({
children,
showSideBar,
backgroundColor,
getTagsFromServer,
getCategoriesFromServer,
}) {
React.useEffect(() => {
getTagsFromServer();
getCategoriesFromServer();
}, []);
return (
<StyledDashbordLayout>
<NavBar />
<SideBarDrawer />
<Grid container className="container">
{showSideBar && (
<Grid item className="sidebar-section">
<SideBar />
</Grid>
)}
<Grid item className="content">
{children}
</Grid>
</Grid>
</StyledDashbordLayout>
);
}

How to use React hook in a react class?

As a newbie in JS world i am in a big trouble ...
I am using a react hook
import { useKeycloak } from '#react-keycloak/web';
import { useCallback } from 'react';
export const useAuthenticatedCallback = (callbackFn) => {
const [keycloak, initialized] = useKeycloak()
const authCallback = useCallback(() => {
// Do nothing while Keycloak is initializing
if (!initialized) {
return
}
// if user is not authenticated redirect to login
if (!keycloak.authenticated) {
return keycloak.login()
}
// otherwise invoke function
return callbackFn()
}, [callbackFn, initialized, keycloak])
return authCallback
}
and able to use inside a function
import React from "react";
import {Grid, Avatar, Chip } from '#material-ui/core';
import { useAuthenticatedCallback } from '../../shared/keycloak/KeycloakOnDemand'
// Tranding function component
function Tranding(props) {
const yourCallback = () => {
// The code you need to be authenticated to run
return yourCallback;
};
const authenticatedCallback = useAuthenticatedCallback(yourCallback);
return (
<Grid container spacing={3}>
<Grid className="text-center" item sm={12} xs={12} md={2}>
<h4>Trending..</h4>
</Grid>
<Grid item md={10}>
<div className="trending-container">
<button onClick={authenticatedCallback} label="ClickMe"/>
</div>
</Grid>
</Grid>
);
}
// export the component.
export default Tranding;
Upto here everything fine and things are working according to requirement.
Now i got a challenge to use same hook inside a react component class ,but fail to achieve this ..Can anyone help for this issue?
I was trying to use in this class
import React from "react";
import {connect} from 'react-redux';
import PostList from "./PostList";
import Grid from '#material-ui/core/Grid';
import Switch from '#material-ui/core/Switch';
import Card from '#material-ui/core/Card';
import CardContent from '#material-ui/core/CardContent';
import Autocomplete from '#material-ui/lab/Autocomplete';
import { TextField, ButtonGroup, Button } from '#material-ui/core';
import SaveIcon from '#material-ui/icons/Save';
import TextEditor from './TextEditor';
//import CKTextEditor from '../../shared/CKTextEditor';
import {NotificationContainer, NotificationManager} from 'react-notifications';
import CircularSpinner from '../../shared/CircularSpinner';
import postService from '../../services/PostService';
class Posts extends React.Component {
constructor() {
super()
this.state = {
posts: [],
totalPages: 0,
isLoading: false,
postForm: {
isValidationActive: false,
tradeTypeId: 1,
tradeTypeText: 'Buy',
price: '', priceValid: false,
stopLoss: '', stopLossValid: false,
targetPrice: '', targetPriceValid: false,
targetDate: '', targetDateValid: false,
title: '',
notes: '', notesValid: false
},
analysisForm: {
isValidationActive: false,
title: '', titleValid: false,
notes: '', notesTemp:'', notesValid: false
},
isTradeCallActive: true,
tradeCallFormValid: false,
analysisFormValid: false,
companyCode: '',
companyValid: false,
postTypes: [],
tradeCallTypes: [],
companies: [],
tradeTypeSelected: 'Buy'
};
this.formRef = null;
this.handleChange = this.handleChange.bind(this);
this.onCompanyCodeChange = this.onCompanyCodeChange.bind(this);
this.handleEditorChange = this.handleEditorChange.bind(this);
this.handleTradeCallSubmit = this.handleTradeCallSubmit.bind(this);
this.handleAnalysisSubmit = this.handleAnalysisSubmit.bind(this);
this.loadFormModel = this.loadFormModel.bind(this);
this.clearTradeCallForm = this.clearTradeCallForm.bind(this);
this.clearAnalysisForm = this.clearAnalysisForm.bind(this);
this.loadPosts = this.loadPosts.bind(this);
}
// handle chnage events for all controls.
handleChange(event) {
let _postForm = this.state.postForm;
let _isTradeCallActive = this.state.isTradeCallActive;
let _targetValue = event.target.value;
let _companyValid = this.state.companyValid;
let _companyCode = this.state.companyCode;
if(event.target.name === 'TradeCall' || event.target.name === 'Analysis'){
if(event.target.name === 'Analysis' && event.target.checked) {_isTradeCallActive = false;}
if(event.target.name === 'TradeCall' && event.target.checked) {_isTradeCallActive = true;}
}
if(event.target.name === 'txtCompany') {
_companyCode = _targetValue;
if (_targetValue.length < 3) { _companyValid = false; }
}
if(event.target.name === 'txtTitle'){
let _analysisForm = this.state.analysisForm;
_analysisForm.titleValid = true;
_analysisForm.title = _targetValue;
if (_targetValue.length < 10) { _analysisForm.titleValid = false; }
let _analysisFormValid = false;
if(_analysisForm.titleValid && _analysisForm.notesValid) {
_analysisFormValid = true;
}
this.setState({ ...this.state, analysisForm: _analysisForm, analysisFormValid: _analysisFormValid});
return;
}
if(event.target.name === 'txtPrice'
|| event.target.name === 'txtStoploss'
|| event.target.name === 'txtTarget'
|| event.target.name === 'notesTextArea'
|| event.target.name === 'targetDate'
|| event.target.name === 'selectTradeType'){
if(event.target.name === 'txtPrice') {
_postForm.priceValid = true;
_postForm.price = _targetValue;
if (_targetValue.length < 1 || _targetValue < 1) { _postForm.priceValid = false; }
}
if(event.target.name === 'txtStoploss') {
_postForm.stopLossValid = true;
_postForm.stopLoss = _targetValue;
if (_targetValue.length < 1 || _targetValue < 1) { _postForm.stopLossValid = false; }
}
if(event.target.name === 'txtTarget') {
_postForm.targetPriceValid = true;
_postForm.targetPrice = _targetValue;
if (_targetValue.length < 1 || _targetValue < 1) { _postForm.targetPriceValid = false; }
}
if(event.target.name === 'notesTextArea') {
_postForm.notesValid = true;
_postForm.notes = _targetValue;
if (_targetValue.length < 20) { _postForm.notesValid = false; }
}
if(event.target.name === 'targetDate') {
_postForm.targetDateValid = true;
_postForm.targetDate = _targetValue;
if (_targetValue.length < 8) { _postForm.targetDateValid = false; }
}
}
let _tradeType = this.state.tradeCallTypes.find(x => x.Name === this.state.tradeTypeSelected)
_postForm.tradeTypeId = _tradeType.Id;
_postForm.tradeTypeText = _tradeType.Name;
let _tradeCallFormValid = false;
if(this.state.companyValid && _postForm.priceValid && _postForm.stopLossValid && _postForm.targetPriceValid && _postForm.targetDateValid && _postForm.notesValid) {
_tradeCallFormValid = true;
_postForm.title = `${_postForm.tradeTypeText} ${this.state.companyCode} at price ${_postForm.price} for target ${_postForm.targetPrice} by date ${_postForm.targetDate} with SL ${_postForm.stopLoss}`;
}
this.setState({ ...this.state, postForm: _postForm, tradeCallFormValid: _tradeCallFormValid, isTradeCallActive: _isTradeCallActive, companyValid: _companyValid, companyCode: _companyCode });
};
// handle trade call submit click.
handleTradeCallSubmit(){
if(this.state.tradeCallFormValid){
// To DO
this.setState({ ...this.state, tradeCallFormValid: false});
let _postForm = this.state.postForm;
let _companyCode = this.state.companyCode;
let requestBody = {
eventType:'create-trade-call-post',
callType:_postForm.tradeTypeId,
symbol:_companyCode,
userId: this.props.activeUser.Id,
price:_postForm.price,
stopLoss:_postForm.stopLoss,
targetPrice:_postForm.targetPrice,
targetDate:_postForm.targetDate,
tags: _companyCode,
title:_postForm.title,
notes:_postForm.notes
}
postService.create(requestBody)
.then((result) => {
NotificationManager.success(`Trade call post created successfully...`);
this.loadPosts(1);
this.clearTradeCallForm();
}).catch((error) => {
NotificationManager.error(`Trade call post creation failed..`);
console.log(`Error: ${error}`);
});
} else {
let _postForm = this.state.postForm;
_postForm.isValidationActive = true;
this.setState({ ...this.state, postForm: _postForm});
}
}
// component did mount event called after the virtual DOM loaded.
componentDidMount() {
this.setState({ ...this.state, isLoading: true });
this.loadFormModel();
}
render() {
if (this.state.isLoading) {
return <CircularSpinner />;
}
return (
<div>
<NotificationContainer/>
<Card>
<CardContent>
<form ref={(ref) => this.formRef = ref} noValidate autoComplete="off">
<Grid className="text-center" container spacing={2}>
{
this.state.postTypes.map((postType, index) =>
<Grid key={postType.Id} item sm={6} xs={6} md={3}>
<h5>{postType.Name} <Switch key={postType.Id} checked={(postType.Name === 'TradeCall')?this.state.isTradeCallActive: !this.state.isTradeCallActive} value={postType.Id} onChange={this.handleChange} name={postType.Name} inputProps={(postType.Name === 'TradeCall') ? {'aria-label': 'secondary checkbox' }: { 'aria-label': 'primary checkbox' }} /></h5>
</Grid>
)
}
<Grid item sm={12} xs={12} md={6}>
<Autocomplete
id="companyAutocomplete"
options={this.state.companies}
getOptionLabel={(option) => option.Symbol}
onInputChange={this.onCompanyCodeChange}
fullWidth
renderInput={(params) => <TextField fullWidth id="txtCompany" {...params}
error={((this.state.postForm.isValidationActive || this.state.analysisForm.isValidationActive))
&& !this.state.companyValid} name="txtCompany" size="small" label="Company" onChange={this.handleChange} variant="outlined" placeholder="Company.." />}
/>
</Grid>
</Grid>
<div className={!this.state.isTradeCallActive ? 'hidden' : ''}>
<Grid container spacing={2}>
<Grid item sm={12} xs={12} md={2}>
<ButtonGroup fullWidth aria-label="small button group">
<Button onClick={()=>{this.setState({ ...this.state, tradeTypeSelected: "Sale"})}}
variant={(this.state.tradeTypeSelected === "Buy") ? "outlined" : "contained"}
color={(this.state.tradeTypeSelected === "Buy") ? "default" : "secondary"}> Sale
</Button>
<Button onClick={()=>{this.setState({ ...this.state, tradeTypeSelected: "Buy"})}}
variant={(this.state.tradeTypeSelected === "Buy") ? "contained" : "outlined"}
color={(this.state.tradeTypeSelected === "Buy") ? "secondary" : "default"}> Buy
</Button>
</ButtonGroup>
</Grid>
<Grid item sm={12} xs={12} md={2}>
<TextField fullWidth id="txtPrice" error={this.state.postForm.isValidationActive && !this.state.postForm.priceValid} name="txtPrice" type="number" InputProps={{ inputProps: { min: 0} }} size="small" label="Price" onChange={this.handleChange} variant="outlined" placeholder="Price.." />
</Grid>
<Grid item sm={12} xs={12} md={2}>
<TextField fullWidth id="txtStoploss" error={this.state.postForm.isValidationActive && !this.state.postForm.stopLossValid} name="txtStoploss" type="number" InputProps={{ inputProps: { min: 0} }} size="small" label="Stoploss" onChange={this.handleChange} variant="outlined" placeholder="SL.." />
</Grid>
<Grid item sm={12} xs={12} md={2}>
<TextField fullWidth id="txtTarget" error={this.state.postForm.isValidationActive && !this.state.postForm.targetPriceValid} name="txtTarget" type="number" InputProps={{ inputProps: { min: 0} }} size="small" label="Target price" onChange={this.handleChange} variant="outlined" placeholder="Price.." />
</Grid>
<Grid item sm={12} xs={12} md={4}>
<TextField fullWidth id="targetDate" error={this.state.postForm.isValidationActive && !this.state.postForm.targetDateValid} name="targetDate" onChange={this.handleChange} type="date" size="small" label="Target date" variant="outlined" InputLabelProps={{ shrink: true, }} />
</Grid>
</Grid>
<Grid container spacing={2}>
<Grid item sm={12} xs={12} md={12}>
<TextField id="notesTextArea" error={this.state.postForm.isValidationActive && !this.state.postForm.notesValid} name="notesTextArea" onChange={this.handleChange} size="medium" fullWidth
placeholder="Enter notes here.." variant="outlined" label="Notes"
multiline rows={3} rowsMax={4} />
</Grid>
</Grid>
<Grid justify="center" container spacing={2}>
<Grid item sm={12} xs={12} md={3}>
<Button size="medium" fullWidth id="btnSubmit" startIcon={<SaveIcon />} onClick={this.handleTradeCallSubmit} variant="contained" color="primary"> Save </Button>
</Grid>
</Grid>
</div>
</form>
</CardContent>
</Card>
<Grid container spacing={3}>
<Grid item md={12}>
<PostList totalPages={this.state.totalPages} posts={this.state.posts} loadPosts={this.loadPosts} />
</Grid>
</Grid>
</div>
)
}
}
// Map redux state to props
const mapStateToProps = state => ({
activeUser: state.session.activeUser
});
// export the component.
export default connect(mapStateToProps)(Posts);
So before calling handleTradeCallSubmit() method i want to check user is login or not if not login redirect to login page otherwise process the method?
You can not use a Hook inside a react Class.
Hooks are functions that let you “hook into” React state and lifecycle
features from function components. Hooks don’t work inside classes —
they let you use React without classes. (We don’t recommend rewriting
your existing components overnight but you can start using Hooks in
the new ones if you’d like.)
https://reactjs.org/docs/hooks-overview.html#:~:text=Hooks%20are%20functions%20that%20let,if%20you'd%20like.)
Although use hooks cannot be used inside a class component, hook components can be used inside a class component.
So one solution is to create a component that uses the hook, and then use the component inside the class instead.
function AuthenticatedCallback(props) {
const authenticatedCallback = useAuthenticatedCallback(props.callbackFn);
return props.children(authenticatedCallback);
}
//from inside the class component.
......
return (
<AuthenticatedCallback>{authenticatedCallback =>
<Grid container spacing={3}>
<Grid className="text-center" item sm={12} xs={12} md={2}>
<h4>Trending..</h4>
</Grid>
<Grid item md={10}>
<div className="trending-container">
<button onClick={authenticatedCallback} label="ClickMe"/>
</div>
</Grid>
</Grid>}
</AuthenticatedCallback>
);
Notice how I'm using the props.children as a functional callback to pass this down to the component.

Resetting a form when using onBlur as opposed to onChange

I had a form that has a lot of lag due to a large amount of state being handled for user's with a large number of job posts etc. I am trying to subdue this lag my switching my onChange to onBlur, this works great. The only problem is that my form no longer gets set to InitialState( empty string). I also have a submit button that I am keeping invalid until all inputs are filled. due to the onblur it remains invalid until I click away from the form. Is there a way I can still reset a form when using onBlur?? and does anyone have a solution to the issue of my button remaining invalid until I click away from the form. My inputs code are as follows:
the handleSubmit function:
const handleSubmit = async e => {
e.preventDefault()
setIsLoading(true)
const fireToken = await localStorage.FBIdToken
await axios
.post(`/job`, formData, {
headers: {
Authorization: `${fireToken}`
}
})
.then(res => {
setOpen(true)
setMessage(res.data)
fetchUser()
setIsLoading(false)
setIsModalOpen(false)
setFormData(INITIAL_STATE)
})
.catch(err => {
setErrors(err.response.data)
console.log(err)
setIsLoading(false)
})
}
The form code:
import React from 'react'
// components
import SelectStatus from './SelectStatus'
// Material UI Stuff
import CircularProgress from '#material-ui/core/CircularProgress'
import Typography from '#material-ui/core/Typography'
import TextField from '#material-ui/core/TextField'
import CardContent from '#material-ui/core/CardContent'
import Button from '#material-ui/core/Button'
import Card from '#material-ui/core/Card'
import Grid from '#material-ui/core/Grid'
// JobCardStyles
import useJobCardStyles from '../styles/JobCardStyles'
const NewJobForm = React.forwardRef(
({ handleSubmit, formData, handleInputChange, isloading }, ref) => {
const { company, position, status, link } = formData
const isInvalid = !company || !position || !link || !status || isloading
const classes = useJobCardStyles()
return (
<Card className={classes.card}>
<CardContent className={classes.content}>
<form noValidate onSubmit={handleSubmit} className={classes.form}>
<Grid
container
spacing={2}
alignItems="center"
justify="space-between"
>
<Grid item sm="auto" xs={12} className={classes.grid}>
<Typography>New</Typography>
<Typography>Job</Typography>
</Grid>
<Grid item sm={3} xs={12} className={classes.grid}>
<TextField
className={classes.jobField}
margin="normal"
fullWidth
id="company"
type="company"
label="Company"
name="company"
autoComplete="company"
defaultValue={company}
onBlur={handleInputChange('company')}
/>
</Grid>
<Grid item sm={3} xs={12} className={classes.grid}>
<TextField
className={classes.jobField}
margin="normal"
fullWidth
id="position"
type="position"
label="Position"
name="position"
autoComplete="position"
defaultValue={position}
onBlur={handleInputChange('position')}
/>
</Grid>
<Grid item sm={2} xs={12} className={classes.grid}>
<SelectStatus
status={status}
handleInputChange={handleInputChange}
/>
</Grid>
<Grid item sm={2} xs={12} className={classes.grid}>
<TextField
className={classes.jobField}
margin="normal"
fullWidth
id="link"
type="text"
label="Link"
name="link"
autoComplete="link"
defaultValue={link}
onBlur={handleInputChange('link')}
/>
</Grid>
<Grid item sm={1} xs={12} className={classes.grid}>
<Button
fullWidth
type="submit"
variant="contained"
color="primary"
disabled={isInvalid}
className={classes.submit}
disableElevation
>
Submit
{isloading && (
<CircularProgress size={30} className={classes.progress} />
)}
</Button>
</Grid>
</Grid>
</form>
</CardContent>
</Card>
)
}
)
export default NewJobForm
Try making another function to wrap several functions.
const NewJobForm = React.forwardRef(
//other logic
const reset = () => {//your reset function logic}
//ver 1
const handleOnBlur = (fn, relatedParam) => {
reset();
fn(relatedParam);
}
//ver 2
const handleOnBlur = (relatedParam) => {
reset();
handleInputChange(relatedParam);
}
return (
<TextField
//other props
onBlur={() => handleOnBlur('company')}
/>
)

extract object items in object array at react template

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>
)

Passing Parameter from Child to Parent trough Input React

I try to pass some information from an input field in the child to the parent.
What i have so far is this:
Parent
import React from "react";
import PropTypes from "prop-types";
import Grid from "#material-ui/core/Grid";
import Paper from "#material-ui/core/Paper";
import Typography from "#material-ui/core/Typography";
import { withStyles } from "#material-ui/core/styles";
import TimelineWidget from "./timeline-widget/timeline-widget.component";
import ContainerTable from "./container-table/container-table.component";
import HistoryTable from "./history-table/history-table.component";
import ShippingOverview from "./shipping-overview/shipping-overview.component";
import MapWidget from "./map-widget/map-widget.component";
import styles from "./shippingInformation.style";
class shippingInformation extends React.Component {
constructor() {
super();
this.inputChange = this.inputChange.bind(this);
}
state = {
searchString: null
};
inputChange(input){
this.setState({ searchString: input });
};
render() {
const { classes } = this.props;
return (
<div className={classes.DashboardPageWrapper}>
<Grid item xs={12}>
<Grid container justify="center" spacing={16}>
<Grid
key={1}
item
xs={12}
sm={12}
md={9}
className={classes.Widget}
>
<Typography
variant="subheading"
className={classes.WidgetHeading}
>
Timeline of Container #
</Typography>
<Paper className={classes.WidgetContent}>
<TimelineWidget />
</Paper>
</Grid>
<Grid
key={2}
item
xs={12}
sm={12}
md={3}
className={classes.Widget}
>
<Typography
variant="subheading"
className={classes.WidgetHeading}
>
Shipping Overview
</Typography>
<Paper className={classes.WidgetContent}>
<ShippingOverview />
</Paper>
</Grid>
</Grid>
<Grid container justify="center" spacing={16}>
<Grid item xs={12} sm={12} md={9}>
<Grid container justify="center" spacing={16}>
<Grid key={3} item xs={12} className={classes.Widget}>
<Typography
variant="subheading"
className={classes.WidgetHeading}
>
Containers
</Typography>
<Paper className={classes.WidgetContent}>
<ContainerTable />
</Paper>
</Grid>
<Grid key={4} item xs={12} className={classes.Widget}>
<Typography
variant="subheading"
className={classes.WidgetHeading}
>
Status History
</Typography>
<Paper className={classes.WidgetContent}>
<HistoryTable />
</Paper>
</Grid>
</Grid>
</Grid>
<Grid
key={5}
item
xs={12}
sm={12}
md={3}
className={classes.Widget}
>
<Typography
variant="subheading"
className={classes.WidgetHeading}
>
Latest Position
</Typography>
<Paper className={classes.WidgetContent}>
<MapWidget onShippingOverview={this.inputChange.bind(this)} />
</Paper>
</Grid>
</Grid>
</Grid>
</div>
);
}
}
shippingInformation.propTypes = {
classes: PropTypes.shape({}).isRequired
};
export default withStyles(styles, { withTheme: true })(shippingInformation);
Child
import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "#material-ui/core/styles";
import Typography from "#material-ui/core/Typography";
import TextField from "#material-ui/core/TextField";
import { Bar } from "react-chartjs-2";
import CountUp from "react-countup";
import classNames from "classnames";
import themeStyles from "./shipping-overview.theme.style";
const styles = theme => ({
container: {
display: "flex",
flexWrap: "wrap"
},
textField: {
marginLeft: theme.spacing.unit,
marginRight: theme.spacing.unit,
width: 200
},
menu: {
width: 200
}
});
export class ShippingOverview extends React.Component {
state = {
searchString: null
};
handleChange(event){
this.setState ({ searchString: event.target.value}, () => {
this.props.onShippingOverview(this.state.searchString);
})
// this.props.onShippingOverview(input);
};
render() {
const { classes } = this.props;
return (
<div className={classes["shipping-overview-widget"]}>
<div>
<form className={classes.container} noValidate autoComplete="off">
<TextField
ref="result"
id="full-width"
label="Tracking ID"
InputLabelProps={{
shrink: true
}}
placeholder="Placeholder"
fullWidth
margin="normal"
onChange={this.handleChange.bind(this)}
value={this.state.input}
/>
</form>
</div>
</div>
);
}
}
ShippingOverview.propTypes = {
theme: PropTypes.shape({
palette: PropTypes.shape({
primary: PropTypes.shape({
dark: PropTypes.string,
main: PropTypes.string,
light: PropTypes.string,
contrastText: PropTypes.string
}),
secondary: PropTypes.shape({
main: PropTypes.string
}),
common: PropTypes.shape({
white: PropTypes.string
})
})
}).isRequired,
classes: PropTypes.shape({}).isRequired
};
export default withStyles(themeStyles, { withTheme: true })(ShippingOverview);
When i now check in the child file only to check the state of searchString it (with console.log()) it seems to work. But as soon as i let it run trough the handleChange function in the child it gives me this error:
> > TypeError: _this2.props.onChild is not a function
33 | handleChange(event){
34 | this.setState ({ searchString: event.target.value}, () => {
> 35 | this.props.onChild(this.state.searchString);
hope someone can help. btw im a noob...
You are using the wrong component in your parent component. Your child component is imported as ShippingOverview but you are using MapWidget. Change to ShippingOverview and it will work.
<ShippingOverview onShippingOverview={this.inputChange} />

Categories

Resources