REACT component update - reactjs

I have this code where sets state on text field change.
and it also may get it's values from the props. It all works fine when I set state from the props value but I can not delete the text field values or change them.
componentDidUpdate(){
if (this.search.nid && this.state.nid !== this.search.nid) this.setState({ ...this.state, nid: this.search.nid })
if (this.search.cif && this.state.cif !== this.search.cif) this.setState({ ...this.state, cif: this.search.cif })
if (this.search.deposit && this.state.deposit !== this.search.deposit)
this.setState({ ...this.state, deposit: this.search.deposit })
}
render() {
this.deposits = this.props.permissions.permissions ? this.props.permissions.permissions : this.props.permissions
this.search = this.props.permissions.search ? this.props.permissions.search : {}
const features = this.props.config.features
return (
<div className='container'>
<div className={'shapeSection'}>
<i style={{ margin: '6px', fontSize: '25px' }} className='fa fa-check-circle' />
<h2>مدیریت دسترسی</h2>
</div>
<Form className={Style.formWrapper} onSubmit={e => {
e.preventDefault()
}}>
<FormGroup className='row'>
<Col sm={10}>
<Row>
<div className='floating-label col-4'>
<input className='floating-input floating-input-height1' type='text' placeholder=' ' name='nid'
onKeyPress={this.handleKeyPress}
onClick={this.handleClick}
onChange={(e) => this.setState({ ...this.state, nid: e.target.value })}
maxLength='15' value={this.state.nid} />
<label className='cust-label'>شناسه مشتری(کدملی،کداتباع،کدسیستم)</label>
</div>
{!features.hideCifInputInPermission.enable && <div className='floating-label col-4'>
<input className='floating-input floating-input-height1' type='text' placeholder=' ' name='cif'
onKeyPress={this.handleKeyPress}
onClick={this.handleClick}
value={this.state.cif}
onChange={(e) => this.setState({ ...this.state, cif: e.target.value })}
maxLength='15' />
<label className='cust-label'>شماره مشتری</label>
</div>}
<div className='floating-label col-4'>
<input className='floating-input floating-input-height1' type='text' placeholder=' ' name='deposit'
onKeyPress={this.handleKeyPress}
onClick={this.handleClick}
onChange={(e) => this.setState({ ...this.state, deposit: e.target.value })}
maxLength='18' value={this.state.deposit} />
<label className='cust-label'>{`شماره‌${strings.deposit || 'حساب'}`}</label>
</div>
</Row>
<Col sm={12}>
<FormText color="muted">
<span>{this.state.hint}</span>
</FormText>
</Col>
</Col>
<Col sm={2}>
<Button className={`${Style.searchBtn} col-sm-8`} color='info' onClick={this.findAccess}
type='button'>جستجو</Button>
<button onClick={this.handleHintClick} className={Style.hintBTN}>
<FontAwesomeIcon icon='question' />
</button>
</Col>
</FormGroup>
</Form>
{this.deposits.length && (this.state.nid.length || this.state.deposit.length || this.state.cif) ?
<div>
<PermissionsTable alert={this.alert} nid={this.state.nid} deposit={this.state.deposit} cif={this.state.cif} />
</div>
: (
<div>
<PermissionsTable alert={this.alert} />
</div>
)
}
{this.state.modal &&
<PermissionHintModal close={() => {
this.setState({ modal: false })
}} features={features} />
}
</div>
)
}
As you can see, there are no easily noticeable errors but I don't see how I can edit my states.
How can I change the text field values?

If you want to change the values of your text fields then you should only have to change the states of the text fields.
You might also want to look into using hooks as they are recommended by React themselves and they are generally considered much easier to manage.

using hooks can help you on this faster [https://reactjs.org/docs/hooks-intro.html]

Related

Reset input on uncheck checkbox (ReactJS + Formik)

I made this component to create a field if a checkbox is checked, but how can I reset this field value if I write something and then uncheck?
const InputCheckbox = ({name, size}) => {
const [checkAmount, setCheckAmount] = useState(false);
return(
<div>
<label htmlFor={size}>
<Field type="checkbox" name={name} value={size} onClick={()=> {checkAmount === false ? setCheckAmount(true) : setCheckAmount(false)}} />
{size}
</label>
{checkAmount === false ? null : <div className="form-control-amount">
<label htmlFor={`sizeamount.${size}`}>{size}</label>
<Field className="form-control-amount" type="number" name={`sizeamount.${size}`} />
</div>}
</div>
)
}
You can use Formik's setFieldValue function to reset the field when the checkbox is unchecked.
Your component:
const InputCheckbox = ({name, size, setFieldValue }) => {
const [checkAmount, setCheckAmount] = useState(false);
return(
<div>
<label htmlFor={size}>
<Field type="checkbox" name={name} checked={checkAmount} value={size} onClick={()=> {checkAmount === false ? setCheckAmount(true) : setCheckAmount(false); setFieldValue(`sizeamount.${size}`, '')}} />
{size}
</label>
{checkAmount === false ? null : <div className="form-control-amount">
<label htmlFor={`sizeamount.${size}`}>{size}</label>
<Field className="form-control-amount" type="number" name={`sizeamount.${size}`} />
</div>}
</div>
)
}
Usage:
<Formik
initialValues={{
check: true
}}
onSubmit={(values, actions) => {
alert('Form has been submitted');
actions.setSubmitting(false);
}}
>
{({setFieldValue}) => (
<Form>
<InputCheckbox name="check" size={10} setFieldValue ={setFieldValue} />
<button type="submit">Submit</button>
</Form>
)}
</Formik>
Reference: https://formik.org/docs/api/formik
You can
<button
class="btn btn-primary pull-right"
type="reset"
onClick={(e) => {
e.preventDefault();
props.resetForm()
}}
>Eliminar filtros</button>

When i change another form element autocomplete value automatically cleared in Formik React js

The form has two elements.
When I select autocomplete value from emal element and then try to input a text value to titl field, the autocomplete value is automatically changed to empty.
What should I do to fix this issue?
I have tried to change formik initialValues using states but it's not working.
sorry for the language issue. Thanks in advance!
class TicketNew extends React.Component{
state = {
clearForm:false,
spinner:false,
closeForm:false,
emailsugges:[],
}
loadAlldata() {
this.setState({
spinner:false,
})
axios.post(baseUrl+'/api/load_company_list')
.then(res => {
const comanyList = res.data;
const emls = comanyList.emls.map(function(item, i){
return {
value:item.tci, title:item.tcc
}
})
this.setState({
emailsugges:emls
})
})
this.setState({
spinner:false,
})
};
componentDidMount(){
this.loadAlldata();
};
render(){
return(
<React.Fragment>
<Formik
initialValues={{ emal: "", titl: "" }}
validationSchema={formSchema}
>
{
({ errors,
touched,
handleSubmit,
isSubmitting,
handleBlur,
values,
resetForm
}) => (
<div>
<Form onSubmit={handleSubmit}>
<Card>
<CardHeader></CardHeader>
<CardBody>
<Row>
<Col md="5" sm="12">
<FormGroup row className="position-relative">
<Col md="4">
<span>Title</span>
</Col>
<Col md="8">
<Field
type="text"
name="titl"
id="titl"
className={`
form-control ${errors.titl && touched.titl && "is-invalid"}
`}
onBlur={handleBlur('titl')}
/>
{errors.titl &&
touched.titl ? (
<div className="invalid-tooltip mt-25">
{errors.titl}
</div>
) : null}
</Col>
</FormGroup>
</Col>
<Col md="2" sm="12"></Col>
<Col md="5" sm="12">
<FormGroup row className="position-relative"
style={{display:rqst!="1"?'none':''}}
>
<Col md="4">
<span>Email Address</span>
</Col>
<Col md="8">
<Field name="emal"
component={ ({field, form}) =>
<AutoComplete
type="email"
name="emal"
id="emal"
suggestions={this.state.emailsugges}
value={
this.state.emailsugges ?
this.state.emailsugges.find(option =>
option.value === field.value)
: ''}
className={`
form-control ${errors.emal && touched.emal && "is-invalid"}
`}
filterKey="title"
suggestionLimit={4}
/>}
/>
{errors.emal &&
touched.emal ? (
<div className="invalid-tooltip mt-25">
{errors.emal}
</div>
) : null}
</Col>
</FormGroup>
</Col>
</Row>
</CardBody>
</Card>
</Form>
</div>
)}
</Formik>
</React.Fragment>
)
}
};
export default TicketNew;

Why it doesn't save input data to state variable inside <Collapse> tag in React

I'm writing a code to implement a vertical Collapse by using react material UI. But it won't set the Input and TextField values into the state variables. Please help me to find what i did wrong here. Thanks in advance.
Here is the function that is used to handle input changes
handleOnChange = async (event) => {
const field = event.target.name;
if (field === "Announcement") {
if (this.isMount) {
await this.setState({
announcement: event.target.value,
isFormDirty: true,
});
}
}
if (field === "Title") {
if (this.isMount) {
await this.setState({
title: event.target.value,
isFormDirty: true,
});
}
}
};
Part of my render() function
<form>
<div>
<ListItem button onClick={this.handleClickAnnouncement}>
<ListItemAvatar>
<Avatar>
<NotificationImportant/>
</Avatar>
</ListItemAvatar>
<ListItemText primary="Announcements"/>
{this.state.ListAnnouncementOpen === true ? <ExpandMore/> : <ExpandLess/>}
</ListItem>
<Collapse in={this.state.ListAnnouncementOpen} timeout="auto" unmountOnExit>
<div className="row" className = "ml-3" >
<label htmlFor="" className="mandatory">
Title :
</label>
<Input
placeholder="Title"
value={this.state.title}
name="Title"
onChange={this.handleOnChange}
required={true}
/>
</div>
<div className="row ml-3">
<TextField
id="standard-multiline-flexible"
label="Type new Announcement here"
onChange={this.handleOnChange}
className="course-detail-section"
name="Announcement"
required={true}
value={this.state.announcement}
/>
<Avatar onClick={this.addAnnouncement}>
<AddIcon/>
</Avatar>
</div>
</Collapse>
</div>
</form>

How to get values from react FieldArray in formik form with other fields?

I have created a Formik form that contains a field array, form and fieldArray is in two separate classes as separate components.
My form:
<Formik onSubmit = {(values, { setSubmitting }) => { setSubmitting(false);}}
enableReinitialize>
{({handleSubmit, errors})=> (
<Form onSubmit= { handleSubmit }>
<Form.Group as= { Row } controlId= "cpFormGroupTitle" className="required">
<Form.Label className="post-create-label" column sm={ 2 } >
Title
</Form.Label>
<Col sm={ 10 }>
<Field name="title" component={ renderTextField } type="text"
isinvalid={ !!errors.title ? "true": "false" }
placeholder="Title *" />
</Col>
</Form.Group>
<Form.Group as= { Row } controlId= "cpFrmGroupShortDesc" className="required">
<Form.Label className="post-create-label" column sm={ 2 } >
Short Description
</Form.Label>
<Col sm={ 10 }>
<Field name="short-desc" component={ renderTextArea } type="text"
isinvalid={ !!errors.shortDescription ? "true": "false" }
placeholder="Short Description *" />
</Col>
</Form.Group>
<Form.Group as= { Row } controlId= "cpFormGroupFeatures">
<Form.Label className="post-create-label" column sm={ 2 }>
Features
</Form.Label>
<Col sm={ 10 }>
<TextFieldArray initialValues={{ features: [] } } name="features"/>
</Col>
</Form.Group>
<Form.Group as={ Row }>
<Col sm= { { span: 2, offset:2 } }>
<Button type="submit" variant="primary">Submit</Button>
</Col>
<Col sm={ 2 }>
<Button variant="secondary">Save as draft</Button>
</Col>
</Form.Group>
</Form>
)}
</Formik>
Here, <TextFieldArray> is field array , I need to get values from field array when form is submitted.
TextFieldArray:
export const TextFieldArray = (props) => (
<React.Fragment>
<Formik initialValues= { props.initialValues } render={({ values }) => (
<Form>
<FieldArray name= { props.name } render={arrayHelper => (
<div>
{ values[props.name] && values[props.name].length > 0 ?
(
values[props.name].map((item, index) => (
<div key={index}>
<Form.Group as= { Row }>
<div className="col-md-8">
<Field name={`${props.name}.${index}`}
className="form-control"/>
</div>
<div className="col-md-2">
<Button type="button" variant="outline-secondary"
onClick={() => arrayHelper.remove(index)}>
Remove
</Button>
</div>
<div className="col-md-2">
<Button type="button" variant="outline-secondary"
onClick={() => arrayHelper.insert(index, '')}>
Add
</Button>
</div>
</Form.Group>
</div>
))
) : (
<Button type="button" variant="outline-secondary"
onClick={() => arrayHelper.push('')} >
{`Add ${ props.name }`}
</Button>
)
}
</div>
)} />
</Form>
)} />
</React.Fragment>
);
I'm a beginner to ReactJS, so someone help me please, that will be huge help from you all.
Thanks.
To have field array be part of same form as other fields, only have one <Formik> and one <Form>. Then make initialValues on Formik that describes all the fields:
<Formik
initialValues={{ friends: someFriends, random: randomText }}
As seen in the following code from Formik FieldArray docs, with another form field added that is not part of the array:
import React, { useState } from "react";
import ReactDOM from "react-dom";
import { Formik, Form, Field, useField, FieldArray } from "formik";
const someFriends = ["jared", "ian", "brent"];
const randomText = "Four score and seven years ago...";
function MyTextInput({ label, ...props }) {
// useField() returns [formik.getFieldProps(), formik.getFieldMeta()]
// which we can spread on <input> and alse replace ErrorMessage entirely.
const [field, meta] = useField(props);
return (
<>
<label
htmlFor={props.id || props.name}
css={{ backgroundColor: props.backgroundColor }}
>
{label}
</label>
<input className="text-input" {...field} type="text" {...props} />
{meta.touched && meta.error ? (
<div className="error">{meta.error}</div>
) : null}
</>
);
}
// Here is an example of a form with an editable list.
// Next to each input are buttons for insert and remove.
// If the list is empty, there is a button to add an item.
export const FriendList = () => (
<div>
<h1>Friend List</h1>
<Formik
initialValues={{ friends: someFriends, random: randomText }}
onSubmit={values =>
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
}, 500)
}
render={({ values }) => (
<Form>
<MyTextInput label="Random comment" name="random" />
<FieldArray
name="friends"
render={arrayHelpers => (
<div>
{values.friends &&
values.friends.length > 0 &&
values.friends.map((friend, index) => (
<div key={index}>
<Field name={`friends.${index}`} />
<button
type="button"
onClick={() => arrayHelpers.remove(index)} // remove a friend from the list
>
-
</button>
<button
type="button"
onClick={() => arrayHelpers.insert(index, "")} // insert an empty string at a position
>
+
</button>
</div>
))}
{/* Add a new empty item at the end of the list */}
<button type="button" onClick={() => arrayHelpers.push("")}>
Add Friend
</button>
<div>
<button type="submit">Submit</button>
</div>
</div>
)}
/>
</Form>
)}
/>
</div>
);
ReactDOM.render(<FriendList />, document.getElementById("root"));
Code in codesandbox.
I don't think you need to create second form for child component.
You need to just pass the values from the parent to the TextFieldArray
<TextFieldArray values={values.myArr} name="features"/>
And the child component just receive the values and render them (as if it was in the parent component)
export const TextFieldArray = (props) => {
return (
<React.Fragment>
<FieldArray
name= { props.name }
render={arrayHelper => (
<div>
{
props.values[props.name] && props.values[props.name].length > 0 ?
(
props.values[props.name].map((item, index) => (
<div key={index}>
<Form.Group as= { Row }>
<div className="col-md-8">
<Field name={`${props.name}.${index}`} className="form-control"/>
</div>
<div className="col-md-2">
<Button type="button" variant="outline-secondary"
onClick={() => arrayHelper.remove(index)}>
Remove
</Button>
</div>
<div className="col-md-2">
<Button type="button" variant="outline-secondary"
onClick={() => arrayHelper.insert(index, '')}
>
Add
</Button>
</div>
</Form.Group>
</div>
))
) : (
<Button type="button" variant="outline-secondary" onClick={() => arrayHelper.push('')} >
{`Add ${ props.name }`}
</Button>
)
}
</div>
)}
/>
</React.Fragment>
)
Of course don't forget to add the initial values of the array to the parent component.
And finally when you click on the submit button it would give you the values.

How to independently delete dynamically-added input fields in ReactJS

I'm trying to independently delete dynamic inputs in a form in React. I have a user attribute group, and then user attribute children. I need to be able to dynamically add new user attribute groups and children, but then delete those fields without deleting ALL of the child attributes.
Right now, when I delete a child attribute, it deletes one from EACH user attribute group.
I have a working fiddle here that shows my code: https://codesandbox.io/embed/23kr654w80
import React, { Component } from "react";
import { Button, Input, Row, Col, Form, FormGroup, Label } from "reactstrap";
class OfferCriteria extends Component {
constructor(props) {
super(props);
this.state = {
single: "",
attributeSingle: [{ single: "" }],
child: "",
attributeChild: [{ child: " " }]
};
}
handleNameChange = event => {
this.setState({
name: event.target.value
});
};
handleAddSingleAttribute = () => {
this.setState({
attributeSingle: this.state.attributeSingle.concat([{ name: "" }])
});
};
handleRemoveSingleAttribute = idx => () => {
this.setState({
attributeSingle: this.state.attributeSingle.filter(
(s, sidx) => idx !== sidx
)
});
};
handleAddChildAttribute = () => {
this.setState({
attributeChild: this.state.attributeChild.concat([{ child: "" }])
});
};
handleRemoveChildAttribute = idz => () => {
this.setState({
attributeChild: this.state.attributeChild.filter(sidz => idz !== sidz)
});
};
render() {
return (
<div>
<Row>
<Col lg="10">
<hr />
</Col>
<Col lg="2" className="float-right">
<Button color="success" onClick={this.handleAddSingleAttribute}>
Add Attribute Group
</Button>
</Col>
</Row>
{this.state.attributeSingle.map(() => (
<div>
<br />
<Row>
<Col lg="2">
<Label>User Attributes</Label>
</Col>
<Col lg="3" className="float-left">
<FormGroup check inline>
<Input
className="form-check-input"
type="radio"
id="includeUserAttributes"
name="inline-radios"
value="includeUserAttributes"
/>
<Label
className="form-check-label"
check
htmlFor="inline-radio1"
>
Include
</Label>
</FormGroup>
<FormGroup check inline>
<Input
className="form-check-input"
type="radio"
id="excludeUserAttributes"
name="inline-radios"
value="excludeUserAttributes"
/>
<Label
className="form-check-label"
check
htmlFor="inline-radio2"
>
Exclude
</Label>
</FormGroup>
</Col>
<Col lg="4">
<Input
type="text"
name="text-input"
placeholder="This is parent attribute"
/>
</Col>
</Row>
<br />
<Row>
<Col lg="3">
{this.state.attributeChild.map(() => (
<div className="shareholder">
<Input
type="text"
name="text-input"
placeholder="This is child attribute"
/>
</div>
))}
</Col>
<Col lg="3" className="float-right">
{this.state.attributeChild.map(() => (
<div className="shareholder">
<Button
color="primary"
onClick={this.handleAddChildAttribute}
>
Add Attribute Child
</Button>
<br />
</div>
))}
</Col>
<Col lg="3" className="float-right">
{this.state.attributeChild.map(idz => (
<div className="shareholder">
<Button
color="danger"
onClick={this.handleRemoveChildAttribute(idz)}
>
Remove Attribute Child
</Button>
<br />
</div>
))}
</Col>
</Row>
<hr />
</div>
))}
</div>
);
}
}
export default OfferCriteria;
I need these child attributes to delete ONLY in their parent attribute group, instead of deleting all of them from all the attribute groups.
There are a couple of things going wrong with your code, but I'll focus on your initial question.
The problem is that you use the same array of child for all your groups. In order to be correct, you should include the attributeChild state into the attributeSingle objects :
{
attributeSingle: [
{
single: "",
attributeChild: [
{
child: " "
}
]
}
]
}
That way, children remain independent between groups.

Resources