Dynamic input in FieldArray - javascript

i have form, inside i have this part of code:
<FieldArray name="items_list" component={renderItemList} explicitProp={id}/>
<div className="buttons mb-4 text-center">
<div className="btn btn-outline-info mt-4" type="button" onClick={() => push('items_list', undefined)}> Añadir Parametros </div>
</div>
outside of the form i have this:
const renderItemList = ({ fields, explicitProp }) => {
return (
<>
{fields.map((member, index) => (
<>
<div className="row mt-4" key={index}>
<div className="col-md-3">
<h4>{index + 1}- Valor de la Lista </h4>
</div>
<Field
className="form-control"
name={`${member}.idResponse`}
type='text'
component={renderIdResponse}
props={explicitProp + '_E_' + Number(index + 1)}
hidden
/>
<div className="col-md-3 mb-4">
<Field
className="form-control"
name={`${member}.title_item`}
type="text"
component="input"
/>
</div>
<div className="col-md-4">
<FieldArray name={`${member}.value_item`} component={renderValueItems} />
</div>
<div className="col-md-1"
onClick={() => fields.remove(index)}
style={{ cursor: 'pointer' }}
>
❌
</div>
</div>
</>
))}
</>
);
};
const renderValueItems = ({ fields, meta: { error } }) => (
<div className="row">
<div>
<button className="btn btn-outline-primary col-md-12" type="button" onClick={() => fields.push()}>Añadir Sinonimos</button>
</div>
{fields.map((valor, index) => (
<div className="mt-3" key={index}>
<div className="row">
<div className="col-md-10">
<Field
className="form-control"
name={valor}
type="text"
component="input"
label={`Sinónimo ${index + 1}`}
/>
</div>
<div className="col-md-2"
onClick={() => fields.remove(index)}
style={{ cursor: 'pointer' }}
> ❌
</div>
</div>
</div>
))}
{error && <li className="error">{error}</li>}
</div>
);
const renderIdResponse = ({props}) => (
console.log(props),
<Field name='texto' {...props} />
);
I would like to get inside the items_list array the object for every item like this:
"items_list": [
{
"idResponse": CA2_3_E_(index + 1)
"title_item": "RESPUESTA 1",
"value_item": [
"SINONIMO 1",
"SINONIMO 2"
]
}
]
but i can not achieve the idResponse. i pass the 'id' in the form like a explicitProp, and then inside the renderItemList i did try to pass directly a value, created with the explicitProp and index to augment the value.
But not works.
I did try to create i component "renderIdResponse" pass the explicitProp like a prop, and inside try to create the value for every object in the array, but i don't know how.
Some idea.
Thanks

Related

I have input a unique "key" prop but still got error asking me to input it in React

so this is my render, it render basically a ui where a username and their email. it also have the option to add new user but when I run the code in my local host, i get this error in my console: Warning: Each child in a list should have a unique "key" prop.
render() {
return (
<div className="App">
{this.state.users.map((user) => {
return (
<React.Fragment>
<div key={user._id} className="box">
<h3>{user.name}</h3>
<h4>{user.email}</h4>
<button
onClick={() => {
this.beginEdit(user);
}}
>
Update
</button>
<button
onClick={() => {
this.deleteUser(user);
}}
>
Delete
</button>
</div>
</React.Fragment>
);
})}
{this.renderAddUser()}
</div>
);
}
}
this is my AddRenderUser
// render new User
renderAddUser() {
return (
<React.Fragment >
<input
type="text"
placeholder="User name"
value={this.state.newUserName}
onChange={this.updateFormField}
name="newUserName"
/>
<input
type="text"
placeholder="User email"
value={this.state.newUserEmail}
onChange={this.updateFormField}
name="newUserEmail"
/>
<button onClick={this.addUser}>Add</button>
</React.Fragment>
);
}
Although I did put the keys props in my div, so not sure how to correct this error
Your key should be in your top-most element
render() {
return (
<div className="App">
{this.state.users.map((user) => {
return (
<React.Fragment key={user._id}>
<div className="box">
<h3>{user.name}</h3>
<h4>{user.email}</h4>
<button
onClick={() => {
this.beginEdit(user);
}}
>
Update
</button>
<button
onClick={() => {
this.deleteUser(user);
}}
>
Delete
</button>
</div>
</React.Fragment>
);
})}
{this.renderAddUser()}
</div>
);
}
}
You need to add the key prop to the React.Fragment tag like this:
<React.Fragment key={user._id}>
Or please try to use index value instead of user.id as follows:
render() {
return (
<div className="App">
{this.state.users.map((user, i) => {
return (
<React.Fragment key={i}>
<div className="box">
<h3>{user.name}</h3>
<h4>{user.email}</h4>
<button
onClick={() => {
this.beginEdit(user);
}}
>
Update
</button>
<button
onClick={() => {
this.deleteUser(user);
}}
>
Delete
</button>
</div>
</React.Fragment>
);
})}
{this.renderAddUser()}
</div>
);
}

onChange Event not Triggered in React JS

export default function ActionRolesPage(props) {
const [authorities, setAuthorities] = useState([]);
const [name, setName] = useState("");
let list = [];
useEffect(() => {
getAuthorities();
}, []);
const getAuthorities = () => {
doGetAllAuthorities()
.then((res) => {
getValidatedData(res.data, "array").map((data) => (
list.push({ authority: data})
))
setAuthorities(list);
}).catch((e) => {
console.log(e);
})
}
const handleChange = (e) => {
console.log(e);
const { name, checked } = e.target
console.log(name,checked);
let tempUser = authorities.map((user) => (
user.authority === name ? { ...user, isChecked: checked } : user
));
setAuthorities(tempUser);
}
if(authorities.length){
console.log(authorities);
}
return (
<React.Fragment>
<Suspense fallback={<div>Loading....</div>}>
<div className="page-content">
<MetaTags>
<title>Add Role | IG One</title>
</MetaTags>
<Container fluid>
<Breadcrumb
title="Add Role"
breadcrumbItems={[{ title: "Settings" }, { title: "Roles" }, { title: "Add" }]}
/>
<Form onSubmit={handleSubmit}>
<Card>
<CardBody>
<Row className="mb-3">
<label
htmlFor="example-text-input"
className="col-md-2 col-form-label"
>
Name
</label>
<div className="col-md-8 mx-0">
<Input
className="form-control"
type="text"
name="name"
required
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Name Of User "
/>
</div>
</Row>
<br></br>
<br></br>
<Row className="mb-3">
<CardTitle>
Authorities
</CardTitle>
<div className="col-md-2">
{
authorities.map((data,index) => (
<>
<div key={index} style={{ display: "flex" }}>
<div className='col-md-10 mx-0 mt-2'>
<Input type={"checkbox"}
checked={data?.isChecked || false}
name={data.authority}
onChange={(e) => console.log(e)}
className="form-control"
style={{ cursor: "pointer", paddingLeft: "1rem" }}
/></div>
<div>
<label style={{ cursor: "pointer" }} htmlFor={data.authority} className="col-md-50 col-form-label"> {data.authority}</label>
</div>
</div>
</>
))
}
</div>
</Row>
<Row className="d-flex justify-content-center mt-4">
<Button color="dark" type='submit' className="btn-xs" style={{ width: "40%", cursor: "pointer" }}
>
Add Role
</Button>
</Row>
</CardBody>
</Card>
</Form>
</Container>
</div>
</Suspense>
</React.Fragment>
)
}
Here is the whole code. I want to handle multiple checkboxes but onChange Event not triggered. There is a function handleChange it calls when onChange triggered but in my case there is no error seen in console as well as not display any event at console please resolve my doubt.
I also need to update the form getting respose from backend is checked authority name array How to handle checked state in checkbox.
If you have created a custom component for input, pass your onChange handler as prop and call inside the component as onChage event of <input> field. Or if you used any third-party lib, then you just need to pass a callback as prop. Otherwise Try this: <input> instead of <Input>
<input type={"checkbox"}
checked={data?.isChecked || false}
name={data.authority}
onChange={(e) => console.log(e)}
className="form-control"
style={{ cursor: "pointer", paddingLeft: "1rem" }}
/>

Formik reset button doesn't clear the form

I have the following:
<Formik initialValues={{}} onSubmit={data => console.log(data)}>
<Form className="h-full">
<FieldsWrapper className="hide-scrolling-bar">
{filters?.map(filter => (
<FiltersGroup
name={filter.label}
filters={filter.children}
/>
))}
</FieldsWrapper>
<ButtonsWrapper>
<Button type="submit" text="apply all" isPrimary />
<Button
type="reset"
text="clear all"
isWishList
isPrimary={false}
/>
</ButtonsWrapper>
</Form>
</Formik>
however the reset button doesn't clear the form
FILTERGROUP COMPONENT
...
const FiltersGroup = ({filters, name}) => {
const Checkbox = ({
field: {name, value, onChange, onBlur},
id,
label,
className,
...props
}) => {
return (
<div className="flex">
<input
name={name}
id={id}
type="checkbox"
value={label}
onChange={onChange}
onBlur={onBlur}
className="hidden"
{...props}
/>
<SizeLabel htmlFor={id}>{label}</SizeLabel>
</div>
)
}
return (
<div className="mb-10">
<GroupLabel>{name}</GroupLabel>
<div className="flex flex-wrap">
{filters?.map(filter => (
<Field
component={Checkbox}
name={name}
id={`id-${filter}`}
label={filter}
/>
))}
</div>
</div>
)
}
export default FiltersGroup
Once you have the fields into a Formik tag then:
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
validateOnBlur={false}
validateOnChange={false}
onSubmit={async (values, { resetForm }) => {
await onSubmit(values)
resetForm()
}}
>
....
When you click Submit button it reset automatically
EDIT:
Example:
const initialValues = {
name: ''
}
<Formik
initialValues={initialValues}>
{formik => {
console.log('formik props', formik)
return (
<div>
<h1>EDIT USER</h1>
<Form>
<Field name="name" type="text" />
<br/><br/><br/>
<div>
<button type="reset" onClick={()=>formik.resetForm()}>
Reset All
</button>
</div>
</Form>
</div >
)
}}
</Formik >
In your case:
<Formik initialValues={{}} onSubmit={data => console.log(data)}>
{formik => {
<Form className="h-full">
<FieldsWrapper className="hide-scrolling-bar">
{filters?.map(filter => (
<FiltersGroup
name={filter.label}
filters={filter.children}
/>
))}
</FieldsWrapper>
<ButtonsWrapper>
<Button type="submit" text="apply all" isPrimary />
<Button
type="reset"
text="clear all"
isWishList
isPrimary={false}
onClick={()=>formik.resetForm()}
/>
</ButtonsWrapper>
</Form>
}}
</Formik>

How Can I change the property of components of React?

I am new to React and recently started working on it. I know that we cannot change the components properties using the props.
I want to know how can we change the properties of Component?
Below is my code:
Courses.jsx
function Courses(){
return (
<div className="courses">
<h1>Ongoing Courses</h1>
<div className="row">
{CourseData.map((value,index)=>{
return (
<div className="col-md-3">
<Card title={value.title} completed={value.completed} content={value.content} value="Resume !" key={index} id={index} />
</div>
);
})}
</div>
</div>
);
}
Here above i am having a Array of Data named as courseData, I am mapping it on a Card component.
Card.jsx:
function Card(props){
function handleClick(){
}
return (
<div className="card">
<div className="card-body">
<h2 className="card-title">{props.title}</h2>
{props.content}
<br/>
<button className="btn btn-danger" > {props.value}</button>
</div>
</div>
);
}
the CourseData has following properties :
courseData : [{
key,
title,
completed
content}]
I simply want that when ever the button present is card gets clicked then the completed attribute of courseData changed to some different value that is passed through the props .
I have tried a lot but not able to do .
Any help regarding this will be helpful for me .
courseData.jsx:
const notes = [{
key: 1,
title: "some Text",
completed:false,
content: "some Text"
},
{
key: 2,
title: "some Text",
completed:false,
content: "some Text"
}]
export default notes;
Add CourseData to the state of the Courses component. Then add a method to adjust the data there. Pass the method throught props that will be called when clicking button in the Card component:
function Courses() {
const [courseData, setCourseData] = useState(CourseData);
const updateCourseData = (index) => {
courseData.splice(index, 1);
setCourseData(courseData);
}
return (
<div className="courses">
<h1>Ongoing Courses</h1>
<div className="row">
{courseData.map((value,index)=>{
return (
<div className="col-md-3">
<Card title={value.title} updateCourseData={updateCourseData} completed={value.completed} content={value.content} value="Resume !" key={index} id={index} />
</div>
);
})}
</div>
</div>
);
}
in the Card.jsx:
<button onClick={() => props.updateCourseData(props.id)} className="btn btn-danger" > {props.value}</button>
function Courses(){
const [coursesData, setCoursesData] = useState(CourseData)
return (
<div className="courses">
<h1>Ongoing Courses</h1>
<div className="row">
{coursesData.map((value,index)=>{
return (
<div className="col-md-3">
<Card coursesData={coursesData} setCoursesData={setCoursesData} title={value.title} completed={value.completed} content={value.content} value="Resume !" key={index} id={index} />
</div>
);
})}
</div>
</div>
);
function Card({id,title,value,content,coursesData,setCoursesData }){
function handleClick(e){
e.preventDefault()
setCoursesData(coursesData => {
const data = coursesData
data.splice(id,1,{
title: title,
completed: value,
content: content,
key: id
})
return data
})
}
return (
<div className="card">
<div className="card-body">
<h2 className="card-title">{title}</h2>
{content}
<br/>
<button onClick={handleClick} className="btn btn-danger">{value}</button>
</div>
</div>
);

Delete a <div> onClick in React

I would like to delete a search result by clicking on the X icon on the individual card.
The search returns 10 recipes from the API, generating 10 divs. How would I go about removing individual divs onClick of the icon whilst keeping the other divs? Essentially just a remove search result button.
return (
<div className='App'>
<form onSubmit={getSearch} className="search-form">
<InputGroup>
<InputGroupAddon addonType="prepend">
<InputGroupText><FontAwesomeIcon icon={faSearch} /></InputGroupText>
</InputGroupAddon>
<Input className="search-bar" type="text" placeholder="Search for recipe..." value={search} onChange={updateSearch} />
</InputGroup>
<Button color="primary" size="sm" className="search-button" type="submit">Search</Button>
</form>
<div className="recipes">
{recipes.map(recipe => (
<Recipe
key={recipe.recipe.label}
title={recipe.recipe.label}
theUrl={recipe.recipe.url}
image={recipe.recipe.image}
ingredients={recipe.recipe.ingredients}
source={recipe.recipe.source}
healthLabels={recipe.recipe.healthLabels}
servings={recipe.recipe.yield} />
))}
</div>
</div>
const Recipe = ({ title, theUrl, image, ingredients, source, healthLabels, servings }) => {
return (
<div className={style.recipe}>
<FontAwesomeIcon className={style.delete} icon={faTimes} />
<h3 >{title}</h3>
<Badge className={style.badge} color="primary">{source}</Badge>
<p>Serves: <Badge color="primary" pill>{servings}</Badge></p>
<img src={image} alt='food' />
<ol className={style.allergens}>
{healthLabels.map(healthLabel => (
<li>{healthLabel}</li>
))}
</ol>
<div className={style.ingr}>
<ol>
{ingredients.map(ingredient => (
<li>{ingredient.text}</li>
))}
</ol>
<Button className={style.button} outline color="primary" size="sm" href={theUrl} target="_blank">Method</Button>
</div>
<div className={style.info}>
<div className={style.share}>
<WhatsappShareButton url={theUrl}><WhatsappIcon round={true} size={20} /></WhatsappShareButton>
<FacebookShareButton url={theUrl}><FacebookIcon round={true} size={20} /></FacebookShareButton>
<EmailShareButton url={theUrl}><EmailIcon round={true} size={20} /></EmailShareButton>
</div>
</div>
</div>
);
}
Simply update the recipes array and React will update the HTML.
I'm not sure where recipes comes from, but if you set an onClick on, say, <Recipe label="x"> that deletes the corresponding recipe element from recipes, then React should no longer render that recipe.
That should be easy. Here's one way:
add onClick to this
<FontAwesomeIcon onClick={deleteRecipe} className={style.delete} icon={faTimes} />
pass a reference of the function that deletes the recipe.
deleteRecipeHandler = (id) => {
// filter your recipes here such that the new recipes array doesn't contain the recipe
// with the id you're getting here.
// Change the below code how you need
const newRecipes = oldRecipes.filter(recipe => {
return recipe.id !== id;
});
}
{recipes.map(recipe => (
<Recipe
key={recipe.recipe.label}
deleteRecipe={this.deleteRecipeHandler.bind(this,recipe.recipe.id)}
title={recipe.recipe.label}
theUrl={recipe.recipe.url}
image={recipe.recipe.image}
ingredients={recipe.recipe.ingredients}
source={recipe.recipe.source}
healthLabels={recipe.recipe.healthLabels}
servings={recipe.recipe.yield} />
))}
since you're destructuring your props you can use
const Recipe = ({ title, theUrl, image, ingredients, source, healthLabels, servings, deleteRecipe }) => {
return (
<div className={style.recipe}>
<FontAwesomeIcon onClick={deleteRecipe} className={style.delete} icon={faTimes} />

Categories

Resources