Validate dynamic Form Field in ReactJs - javascript

I have a problem validating dynamic form fields (can be added or reduced), I try to use the following library (React Bootstrap4 Form Validation) for validation, but the error message always appears: Uncaught TypeError: firstErrorInput is undefined in the console, can anyone help me, or provide another alternative to create dynamic form fields and how to do the validation? The link image below is an example of the result I want. Thank you in advance.
Example of the result I want
Here is my code:
import React, { useState, useEffect, useRef } from "react";
import { ValidationForm, TextInput } from 'react-bootstrap4-form-validation';
function ModalProductSpec () {
const [inputList, setInputList] = useState([{ product_specTitle: "", product_specDescription: "" }]);
const [loader, setLoader] = useState(false);
const formRefs = useRef();
const handleInputChange = (e, index) => {
const { name, value } = e.target;
const list = [...inputList];
list[index][name] = value;
setInputList(list);
};
const handleAddClick = () => {
setInputList([...inputList, { product_specTitle: "", product_specDescription: "" }]);
};
const handleRemoveClick = index => {
const list = [...inputList];
list.splice(index, 1);
setInputList(list);
};
const handleSubmit = (e) => {
e.preventDefault();
setLoader(true);
console.log(inputList);
}
return (
<div className="modal fade" id="modal-product-add-spec" tabIndex="-1" role="dialog" aria-hidden="true">
<div className="modal-dialog modal-xl" role="document">
<div className="modal-content">
<div className="modal-header bg-danger">
<h5 className="modal-title">Add Specification Product</h5>
<button type="button" className="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<ValidationForm onSubmit={handleSubmit} ref={formRefs}>
<div className="modal-body">
{
inputList.map(( field, index ) => {
return (
<div key={index}>
<div className="row form-group mb-1" >
<div className="col-lg-2 col-sm-2 col-md-2">Spec Title :</div>
<div className="col-lg-2 col-sm-2 col-md-2">
<TextInput type="text" className="form-control" name="product_specTitle" autoComplete="off"
value={field.product_specTitle} onChange={e => handleInputChange(e, index)} required/>
</div>
<div className="col-lg-2 col-sm-2 col-md-2">Spec Description :</div>
<div className="col-lg-5 col-sm-5 col-md-5">
<TextInput type="text" className="form-control" name="product_specDescription" autoComplete="off"
value={field.product_specDescription} onChange={e => handleInputChange(e, index)} multiline rows="5" required/>
</div>
<div className="col-lg-1 col-sm-1 col-md-1 align-self-center">
{inputList.length !== 1 && <button className="btn btn-danger btn-sm mr-1 mt-1 mt-md-0" onClick={() => handleRemoveClick(index)}><i className="fa fa-minus"></i></button>}
{inputList.length - 1 === index && <button className="btn btn-primary btn-sm mt-1 mt-md-0" onClick={handleAddClick}><i className="fa fa-plus"></i></button>}
</div>
</div> <hr />
</div>
)
})
}
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" className="btn btn-danger">
{!loader ? ('Save') : (<span className="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>) }
</button>
</div>
</ValidationForm>
</div>
</div>
</div>
)
}
export default ModalProductSpec;

Try this one.
yarn add react-hook-form
https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn
https://react-hook-form.com/api/usefieldarray

Related

Use [e.target.name]=e.target.value inside object

I have this object:
const itemDataObject = {
sort: '',
title_item_lateral: '',
text_item_lateral: '',
image_lateral: [
{
title_image_lateral: '',
path_image_lateral: '',
},
],
document_lateral: '',
links: [
{
title_link: '',
link: '',
},
],
};
and i need to fill it in a form.
i use this function:
const handleChange = (i, e) => {
let itemData = [...item_lateral];
itemData[i][e.target.name]=e.target.value;
setItems(itemData);
setNewLateral({...lateral, item_lateral, title_lateral});
handleChangeChat(e); };
and this inside the form:
<div>
{item_lateral.map((input, i) => (
<>
{ !(input.button_pressed === 'image' || input.button_pressed ===
'links') &&
<div className="row align-item_lateral-center" key=
{input.button_pressed + i + 1}>
<div className="col-2 mt-3">
<h3>{input.button_pressed}</h3>
</div>
<div className="col-10">
<input
placeholder={input.button_pressed}
id={i}
className='form-control mt-3'
name={input.button_pressed}
onChange= {e => handleChange(i, e)}
type="text"
/>
</div>
</div>
}
{ input.button_pressed === 'image' &&
<>
<div className="row align-item_lateral-center row" key=
{input.button_pressed + i + 2}>
<div className="col-2">
<h3>Imagen: </h3>
</div>
<div className='col-10'>
<input
placeholder='title_image_lateral'
id={i}
className='form-control mt-3'
name='title_image_lateral'
onChange= {e => handleChange(i, e)}
type="text"
/>
</div>
</div>
<div className="row align-item_lateral-center row" key=
{input.button_pressed + i + 1}>
<div className="col-2">
<h3>Image Path: </h3>
</div>
<div className='col-10'>
<input
placeholder='path_image_lateral'
id={i}
className='form-control mt-3'
name='path_image_lateral'
onChange= {e => handleChange(i, e)}
type="text"
/>
</div>
</div>
</>
}
{input.button_pressed === 'links' &&
<>
<div className="row align-item_lateral-center row" key=
{input.button_pressed + i+2}>
<div className="col-2">
<h3>Title Link: </h3>
</div>
<div className="col-8">
<input
placeholder='titel_link'
id={i}
className='form-control mt-3'
name='titel_link'
onChange= {e => handleChange(i, e)}
type="text"
/>
</div>
</div>
<div className="row align-item_lateral-center row" key={i}>
<div className="col-2">
<h3>Link: </h3>
</div>
<div className="col-8">
<input
placeholder='link'
id={i}
className='form-control mt-3'
name='link'
onChange= {e => handleChange(i, e)}
type="text"
/>
</div>
</div>
</>
}
</>
))}
</div>
The form works onsubmit, and create values in the object with the property name, and the value.
But if the property (p.e: 'title_image_lateral'), not put the new value in the correct place in the object, instead create a new element in the root of the object: title_image_lateral: (value submited in the form).
I thik that i can change the 'root' for the itemData[i][e.target.name]=e.target.value; , but i can not achieve.
Maybe i can create state for this values, and then onsubmit the form, set in the object...but maybe is made a big surround.
Some light for my issue.
Thanks.
Here the entire file:
import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
const LateralWindow = ({token}) => {
const itemDataObject = {
sort: '',
title_item_lateral: '',
text_item_lateral: '',
image_lateral: [
{
title_image_lateral: '',
path_image_lateral: '',
},
],
document_lateral: '',
links: [
{
title_link: '',
link: '',
},
],
};
const dispatch = useDispatch();
const generalInfo = useSelector(state=> state.faqsGralInfo);
const {
description,
typeResponse,
rolViews,
workLoadLevel,
id,
id_intent,
corpusArea,
corpusName,
} = generalInfo;
const [ finalResponse, setFinalResponse ] = useState({});
const [ newJsonResponse, setNewJsonResponse ] = useState( {});
const [ title_lateral, setTitleLateral ] = useState('');
const [ item_lateral, setItems ] = useState([]);
const [ lateral, setNewLateral] = useState({
title_lateral: title_lateral,
item_lateral: [item_lateral]
});
let buttonPressed;
const [nameValue, setNameValue] = useState(['inicial']);
console.log(nameValue);
const addFields = (e) => {
e.preventDefault();
buttonPressed = e.target.value;
setNameValue(buttonPressed);
let newItemField;
newItemField = { ...itemDataObject, button_pressed: buttonPressed };
setItems([...item_lateral, newItemField]);
};
const handleChangeChat = (e) => {
setFinalResponse({...finalResponse, [e.target.name]: e.target.value});
setNewJsonResponse({
...newJsonResponse,
accesToken: token,
newDataResponse: {
description,
typeResponse,
rolViews,
workLoadLevel,
id,
id_intent,
response_json_new:{finalResponse, lateral},
corpusArea,
corpusName,
lateral_W: generalInfo.lateral_W === 'true' ? 1 : 0 ,
}
},
);
};
const handleChange = (i, e) => {
let itemData = [...item_lateral];
itemData[i][e.target.name]=e.target.value;
setItems(itemData);
setNewLateral({...lateral, item_lateral, title_lateral});
handleChangeChat(e); };
const submitForm = (e) => {
e.preventDefault();
};
const sendToCorpus = () => {
/* setTimeout(() => {
window.location = '/corpus';
}, 3000); */
};
return (
<>
<div className="card mb-3">
<div className="card-body">
<h2> Diseño Chat </h2>
<form className="row mt-4" onSubmit={submitForm} >
<div className="col-md-1 mb-4">
<label htmlFor="inputDescription" className="form-label text-center">
<h5> Título </h5>
</label>
</div>
<div className="col-md-11">
<input
type="text"
className="form-control"
name='title'
onChange={handleChangeChat}
id="inputDescription"
required
/>
</div>
<div className="col-md-1 mb-4">
<label htmlFor="inputResponse" className="form-label text-center" >
<h5> Texto </h5>
</label>
</div>
<div className="col-md-11">
<input
type="textarea"
className="form-control"
name='text'
onChange={handleChangeChat}
id="inputResponse"
required
/>
</div>
<div className="col-md-1 mb-4">
<label htmlFor="link" className="form-label text-center" >
<h5> Link </h5>
</label>
</div>
<div className="col-md-5">
<input
type="link"
className="form-control"
name="link"
onChange={handleChangeChat}
id="link"
required
/>
</div>
<div className="col-md-1">
<label htmlFor="link_title" className="form-label text-center" >
<h5> Title Link </h5>
</label>
</div>
<div className="col-md-5">
<input
type="text"
className="form-control"
name='link_title'
onChange={handleChangeChat}
id="link_title"
required
/>
</div>
<div className="col-md-1 mb-4">
<label htmlFor="image" className="form-label text-center" >
<h5> Image </h5>
</label>
</div>
<div className="col-md-5">
<input
type="file"
className="form-control"
name="image"
onChange={handleChangeChat}
id="image"
required
/>
</div>
<div className="col-md-1">
<label htmlFor="image_title" className="form-label text-center" >
<h5> Title Image </h5>
</label>
</div>
<div className="col-md-5">
<input
type="text"
className="form-control"
name='image_title'
onChange={handleChangeChat}
id="image_title"
required
/>
</div>
<div className="mt-5" >
<h3>DISEÑO VENTANA LATERAL</h3>
</div>
<h5 className="ms-5 mb-5 mt-5"> Diseña tu respuesta añadidendo subtitulos, texto, imagenes, documentos y enlaces.
Puedes seleccionarlos con el orden que mejor se ajuste a tu respuesta. Y puedes poner tantos elementos como quieras. </h5>
<div className="container">
<div className="row align-item_lateral-center" >
<div className="col-2 mt-3">
<h3>Título Ventana Lateral</h3>
</div>
<div className="col-10">
<input
placeholder= 'Título Ventana Lateral'
className='form-control mt-3'
value={title_lateral}
onChange= {e=> setTitleLateral(e.target.value)}
type="text"
/>
</div>
</div>
<div>
{item_lateral.map((input, i) => (
<>
{ !(input.button_pressed === 'image' || input.button_pressed === 'links') &&
<div className="row align-item_lateral-center" key={input.button_pressed + i + 1}>
<div className="col-2 mt-3">
<h3>{input.button_pressed}</h3>
</div>
<div className="col-10">
<input
placeholder={input.button_pressed}
id={i}
className='form-control mt-3'
name={input.button_pressed}
onChange= {e => handleChange(i, e)}
type="text"
/>
</div>
</div>
}
{ input.button_pressed === 'image' &&
<>
<div className="row align-item_lateral-center row" key={input.button_pressed + i + 2}>
<div className="col-2">
<h3>Imagen: </h3>
</div>
<div className='col-10'>
<input
placeholder='title_image_lateral'
id={i}
className='form-control mt-3'
name='title_image_lateral'
onChange= {e => handleChange(i, e)}
type="text"
/>
</div>
</div>
<div className="row align-item_lateral-center row" key={input.button_pressed + i + 1}>
<div className="col-2">
<h3>Image Path: </h3>
</div>
<div className='col-10'>
<input
placeholder='path_image_lateral'
id={i}
className='form-control mt-3'
name='path_image_lateral'
onChange= {e => handleChange(i, e)}
type="text"
/>
</div>
</div>
</>
}
{input.button_pressed === 'links' &&
<>
<div className="row align-item_lateral-center row" key={input.button_pressed + i+2}>
<div className="col-2">
<h3>Title Link: </h3>
</div>
<div className="col-8">
<input
placeholder='titel_link'
id={i}
className='form-control mt-3'
name='titel_link'
onChange= {e => handleChange(i, e)}
type="text"
/>
</div>
</div>
<div className="row align-item_lateral-center row" key={i}>
<div className="col-2">
<h3>Link: </h3>
</div>
<div className="col-8">
<input
placeholder='link'
id={i}
className='form-control mt-3'
name='link'
onChange= {e => handleChange(i, e)}
type="text"
/>
</div>
</div>
</>
}
</>
))}
</div>
<div className="mt-5 text-center">
<button className="btn btn-primary me-4 mb-4" value="text_item_lateral" onClick={addFields}>
Add Text
</button>
<button className="btn btn-primary me-4 mb-4" value="title_item_lateral" onClick={addFields}>
Add Subtitle
</button>
<button className="btn btn-primary me-4 mb-4" value="image" onClick={addFields}>
Add Image
</button>
<button className="btn btn-primary me-4 mb-4" value="document_lateral" onClick={addFields}>
Add document
</button>
<button className="btn btn-primary me-4 mb-4" value="links" onClick={addFields}>
Add Links
</button>
</div>
</div>
<div>
</div>
<div>
{(isCreated && isVariationsSave) &&
<div className="alert alert-success" role='alert'>
Respuesta CREADA Correctamente
</div>
}
{isCreated && sendToCorpus()}
</div>
<button className="btn btn-warning me-5 mb-3" type="submit" >Preview</button>
<button className="btn btn-success me-5 mb-3" type="submit">Guardar Respuesta</button>
</form>
<div className="text-center">
</div>
</div>
</div>
</>
);
};
export default LateralWindow;
Check if this suits your needs:
import { useState } from "react";
import { useSelector } from "react-redux";
const LateralWindow = ({ token }) => {
const itemDataObject = {
sort: "",
title_item_lateral: "",
text_item_lateral: "",
image_lateral: {
title_image_lateral: "",
path_image_lateral: "",
},
document_lateral: "",
links: {
title_link: "",
link: "",
},
};
const generalInfo = useSelector((state) => state.faqsGralInfo);
const { description, typeResponse, rolViews, workLoadLevel, id, id_intent, corpusArea, corpusName } = generalInfo;
const [finalResponse, setFinalResponse] = useState({});
const [newJsonResponse, setNewJsonResponse] = useState({});
const [title_lateral, setTitleLateral] = useState("");
const [item_lateral, setItems] = useState([]);
const [lateral, setNewLateral] = useState({
title_lateral: title_lateral,
item_lateral: [item_lateral],
});
let buttonPressed;
const addFields = (e) => {
e.preventDefault();
buttonPressed = e.target.value;
let newItemField;
newItemField = { ...itemDataObject, button_pressed: buttonPressed };
setItems([...item_lateral, newItemField]);
};
const handleChangeChat = (e) => {
setFinalResponse({ ...finalResponse, [e.target.name]: e.target.value });
setNewJsonResponse({
...newJsonResponse,
accesToken: token,
newDataResponse: {
description,
typeResponse,
rolViews,
workLoadLevel,
id,
id_intent,
response_json_new: { finalResponse, lateral },
corpusArea,
corpusName,
lateral_W: generalInfo.lateral_W === "true" ? 1 : 0,
},
});
};
const handleChange = (i, e) => {
let itemData = [...item_lateral];
let elementChanged = e.target;
let name = elementChanged.name;
let value = elementChanged.value;
if (name === "title_image_lateral" || name === "path_image_lateral") {
itemData[i].image_lateral[name] = value;
} else if (name === "title_link" || name === "link") {
itemData[i].links[name] = value;
} else {
itemData[i][name] = value;
}
setItems(itemData);
setNewLateral({ ...lateral, item_lateral, title_lateral });
handleChangeChat(e);
};
const submitForm = (e) => {
console.log(item_lateral);
e.preventDefault();
};
return (
<>
<div className="card mb-3">
<div className="card-body">
<h2> Diseño Chat </h2>
<form className="row mt-4" onSubmit={submitForm}>
<div className="col-md-1 mb-4">
<label htmlFor="inputDescription" className="form-label text-center">
<h5> Título </h5>
</label>
</div>
<div className="col-md-11">
<input type="text" className="form-control" name="title" value="Titulo" onChange={handleChangeChat} id="inputDescription" required />
</div>
<div className="col-md-1 mb-4">
<label htmlFor="inputResponse" className="form-label text-center">
<h5> Texto </h5>
</label>
</div>
<div className="col-md-11">
<input type="textarea" className="form-control" name="text" value="Texto" onChange={handleChangeChat} id="inputResponse" required />
</div>
<div className="col-md-1 mb-4">
<label htmlFor="link" className="form-label text-center">
<h5> Link </h5>
</label>
</div>
<div className="col-md-5">
<input type="link" className="form-control" name="link" value="link" onChange={handleChangeChat} id="link" required />
</div>
<div className="col-md-1">
<label htmlFor="link_title" className="form-label text-center">
<h5> Title Link </h5>
</label>
</div>
<div className="col-md-5">
<input type="text" className="form-control" name="link_title" value="testeLink" onChange={handleChangeChat} id="link_title" required />
</div>
<div className="col-md-1 mb-4">
<label htmlFor="image" className="form-label text-center">
<h5> Image </h5>
</label>
</div>
<div className="col-md-5">
<input type="file" className="form-control" name="image" onChange={handleChangeChat} id="image" required />
</div>
<div className="col-md-1">
<label htmlFor="image_title" className="form-label text-center">
<h5> Title Image </h5>
</label>
</div>
<div className="col-md-5">
<input
type="text"
className="form-control"
name="image_title"
value="title image"
onChange={handleChangeChat}
id="image_title"
required
/>
</div>
<div className="mt-5">
<h3>DISEÑO VENTANA LATERAL</h3>
</div>
<h5 className="ms-5 mb-5 mt-5">
Diseña tu respuesta añadidendo subtitulos, texto, imagenes, documentos y enlaces. Puedes seleccionarlos con el orden que mejor se ajuste
a tu respuesta. Y puedes poner tantos elementos como quieras.{" "}
</h5>
<div className="container">
<div className="row align-item_lateral-center">
<div className="col-2 mt-3">
<h3>Título Ventana Lateral</h3>
</div>
<div className="col-10">
<input
placeholder="Título Ventana Lateral"
className="form-control mt-3"
value={title_lateral}
onChange={(e) => setTitleLateral(e.target.value)}
type="text"
/>
</div>
</div>
<div className="mt-5 text-center">
<button className="btn btn-primary me-4 mb-4" value="text_item_lateral" onClick={addFields}>
Add Text
</button>
<button className="btn btn-primary me-4 mb-4" value="title_item_lateral" onClick={addFields}>
Add Subtitle
</button>
<button className="btn btn-primary me-4 mb-4" value="image" onClick={addFields}>
Add Image
</button>
<button className="btn btn-primary me-4 mb-4" value="document_lateral" onClick={addFields}>
Add document
</button>
<button className="btn btn-primary me-4 mb-4" value="links" onClick={addFields}>
Add Links
</button>
</div>
<div>
{item_lateral.map((input, i) => {
return (
<div key={input.button_pressed + i}>
{!(input.button_pressed === "image" || input.button_pressed === "links") && (
<div className="row align-item_lateral-center">
<div className="col-2 mt-3">
<h3>{input.button_pressed}</h3>
</div>
<div className="col-10">
<input
placeholder={input.button_pressed}
id={i}
className="form-control mt-3"
name={input.button_pressed}
onChange={(e) => handleChange(i, e)}
type="text"
/>
</div>
</div>
)}
{input.button_pressed === "image" && (
<>
<div className="row align-item_lateral-center row">
<div className="col-2">
<h3>Imagen: </h3>
</div>
<div className="col-10">
<input
placeholder="title_image_lateral"
id={i}
className="form-control mt-3"
name="title_image_lateral"
onChange={(e) => handleChange(i, e)}
type="text"
/>
</div>
</div>
<div className="row align-item_lateral-center row">
<div className="col-2">
<h3>Image Path: </h3>
</div>
<div className="col-10">
<input
placeholder="path_image_lateral"
id={i}
className="form-control mt-3"
name="path_image_lateral"
onChange={(e) => handleChange(i, e)}
type="text"
/>
</div>
</div>
</>
)}
{input.button_pressed === "links" && (
<>
<div className="row align-item_lateral-center row">
<div className="col-2">
<h3>Title Link: </h3>
</div>
<div className="col-8">
<input
placeholder="title_link"
id={i}
className="form-control mt-3"
name="title_link"
onChange={(e) => handleChange(i, e)}
type="text"
/>
</div>
</div>
<div className="row align-item_lateral-center row">
<div className="col-2">
<h3>Link: </h3>
</div>
<div className="col-8">
<input
placeholder="link"
id={i}
className="form-control mt-3"
name="link"
onChange={(e) => handleChange(i, e)}
type="text"
/>
</div>
</div>
</>
)}
</div>
);
})}
</div>
</div>
<div></div>
<div>
{isCreated && isVariationsSave && (
<div className="alert alert-success" role="alert">
Respuesta CREADA Correctamente
</div>
)}
{isCreated && sendToCorpus()}
</div>
<button className="btn btn-warning me-5 mb-3" type="submit">
Preview
</button>
<button className="btn btn-success me-5 mb-3" type="submit">
Guardar Respuesta
</button>
</form>
<div className="text-center"></div>
</div>
</div>
</>
);
};
export default LateralWindow;

While clicking on Add Task Button my Bootstrap modal is not opening

Tysm for Solving in advance!
I think problem is in <button className="btn" onClick={handleDelete(todo.todo_id)}> in 52th line.
UncompletedTaskView.js is in App.js
import React,{useState} from 'react';
import axios from 'axios';
import AddTask from './AddTask';
import EditButton from './EditButton';
const UncompletedTaskView = () => {
const [todoList,setTodoList] = useState([]);
const [viewCompleted,setViewCompleted] = useState(false);
const refreshList = async () => {
try {
const response = await axios.get("http://localhost:8000/api/tasks/");
response.data.filter( (item) => item.completed === viewCompleted );
setTodoList(response.data);
} catch(err) {
console.log(err.message);
}
};
const handleDelete = async (id) => {
await axios.delete(`http://localhost:8000/api/tasks/${id}/`);
refreshList();
};
return (
<div className="container">
<h1 className='text-black text-uppercase text-center my-4'>Todo List</h1>
<table className="table table-hover">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Mark Completed</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{
todoList.map((todo) => {
return <tr id={todo.todo_id}>
<td>{todo.title}</td>
<td>{todo.description}</td>
<td className="radio">
<label><input type="radio" name="optradio" onClick={() => setViewCompleted(true)}/>Completed</label>
</td>
<td><EditButton refreshList={refreshList}/></td>
<td>
<button className="btn" onClick={handleDelete(todo.todo_id)}>
Delete
</button>
</td>
</tr>
})
}
</tbody>
</table>
<AddTask refreshList={refreshList}/>
</div>);
}
export default UncompletedTaskView;
AddTask.js File
import React,{ useState} from 'react';
import axios from 'axios';
const AddTask = ({ refreshList }) => {
const [title,setTitle] = useState("");
const [description,setDescription] =useState("");
const completed= false;
const handleSubmit = async() => {
const item = {
"title" : title,
"description": description,
"completed": completed
};
try {
await axios.post(`http://localhost:8000/api/tasks/`, item);
refreshList();
} catch (err) {
console.log(err.message);
}
}
return (<div>
<button
type="button"
className="btn btn-success"
data-toggle="modal"
data-target="#myModal">
Add Task
</button>
<div className="container">
<div className="modal fade" id="myModal" role="dialog">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button type="button" className="close" data-dismiss="modal">×</button>
<h4 className="modal-title">Add Task</h4>
</div>
<div className="modal-body">
<label htmlFor="title">Title</label>
<input
type="text"
name="title" value={title}
onChange={ (e) => setTitle(e.target.value)}
placeholder="Task Title" />
<label htmlFor="description">Title</label>
<input
type="text"
name="description" value={description}
onChange={ (e) => setDescription(e.target.value)}
placeholder="Task Description" />
</div>
<div className="modal-footer">
<button type="button" className="btn btn-success" onClick={handleSubmit}>Add</button>
<button type="button" class="btn btn-danger" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</div>)
}
export default AddTask;
Tysm for Solving in advance!
I was using 3.37 but I replaced it with 4.3.1 and it's perfectly working!
#Suresh Thnx!

How to toggle particular tag or component on click

I Have an UI which I am rendering with dynamic data, Inside which I have an editable button on click of which I am hiding one field and rendering one new field that is select option.
Issue
As I am rendering my data dynamically so edit field is in each div so when I am clicking edit it is changing all divs, I want to change the particular div only
Code
const Evaluation = props => {
const [visible, setvisible] = useState(true);
let empData = [
{
firstName: "name1",
lastName: "lastname1",
class: "5"
},
{
firstName: "name2",
lastName: "last name2",
class: "6"
}
];
const onClickEdit = () => {
setvisible(false);
};
const cancelOnClick = () => {
setvisible(true);
};
return (
<div className="container-fluid">
{empData.map(item => (
<div>
<div>
<div className="row">
<div className="form-group col-6 col-sm-6 col-md-6 col-lg-5 col-xl-5">
<input
type="text"
disabled
id="firstName"
value={item.firstName}
/>
<br />
<label htmlFor="firstName" className="labelEmploye">
First name
</label>
</div>
</div>
<div className="row">
<div className="form-group col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
<input
type="text"
disabled
id="lastname"
value={item.lastName}
/>
<br />
<label htmlFor="lastname" className="labelEmploye">
Last Name
</label>
</div>
</div>
{visible ? (
<div className="row">
<div className="form-group col-12 col-sm-12 col-md-12 col-lg-5 col-xl-5">
<input
type="text"
disabled
id="Evaluation"
value={item.class}
/>
<br />
<label htmlFor="Evaluation" className="labelEmploye">
Evaluation
</label>
<div className="form-group mt-2">
<button
className="btn btn-primary form-control col-5 col-sm-5 col-md-3 col-lg-2 col-xl-2"
onClick={onClickEdit}
>
Edit
</button>
</div>
</div>
</div>
) : (
<div className="row">
<div className="form-group col-12 col-sm-12 col-md-6 col-lg-4 col-xl-4">
<select className="form-control">
<option>1</option>
<option>2</option>
</select>
<button
onClick={cancelOnClick}
className="btn btn-warning form-control col-5 col-sm-5 col-md-3 col-lg-2 col-xl-2 m-2"
>
Cancel
</button>
<button className="btn btn-success form-control col-5 col-sm-5 col-md-3 col-lg-2 col-xl-2 m-2">
Save
</button>
</div>
</div>
)}
</div>
<hr />
</div>
))}
</div>
);
Code sandbox link
There's an easier way to do that. See the working demo here: CodeSandBox
Basically, set the empData in your state directly, and add an edit field to each of the objects.
const [empData, setEmpData] = useState([
{
firstName: "name1",
lastName: "lastname1",
class: "5",
edit: false
},
{
firstName: "name2",
lastName: "last name2",
class: "6",
edit: false
}
]);
Add the index as well in the items where you map it:
empData.map((item, index) => ())
Now you can use the edit field to hide/show the edit options:
{!item.edit ? () : ()}
On the buttons you pass values like this:
onClick={() => onClickEdit(index)}
onClick={() => cancelOnClick(index)}
And your functions would be:
const onClickEdit = index => {
let data = [...empData];
data[index].edit = true;
setEmpData(data);
};
const cancelOnClick = index => {
let data = [...empData];
data[index].edit = false;
setEmpData(data);
};
Because
const [visible, setvisible] = useState(true);
is shared state for all what gonna be in App.js, the easiest way to achieve what you want is to shift this and other relevant code from App.js to different component
empData.map(item => <ItemComponent item={item} />)
and in it copy all UI code + the state above. now each component will create his own visible flag
function ItemComponent({item}) {
const [visible, setvisible] = useState(true);
return(
<div>
<div>
<div className="row">
<div className="form-group col-6 col-sm-6 col-md-6 col-lg-5 col-xl-5">
<input
type="text"
disabled
id="firstName"
value={item.firstName}
/>
<br />
<label htmlFor="firstName" className="labelEmploye">
First name
</label>
</div>
</div>
<div className="row">
<div className="form-group col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
<input
type="text"
disabled
id="lastname"
value={item.lastName}
/>
<br />
<label htmlFor="lastname" className="labelEmploye">
Last Name
</label>
</div>
</div>
{visible ? (
<div className="row">
<div className="form-group col-12 col-sm-12 col-md-12 col-lg-5 col-xl-5">
<input
type="text"
disabled
id="Evaluation"
value={item.class}
/>
<br />
<label htmlFor="Evaluation" className="labelEmploye">
Evaluation
</label>
<div className="form-group mt-2">
<button
className="btn btn-primary form-control col-5 col-sm-5 col-md-3 col-lg-2 col-xl-2"
onClick={onClickEdit}
>
Edit
</button>
</div>
</div>
</div>
) : (
<div className="row">
<div className="form-group col-12 col-sm-12 col-md-6 col-lg-4 col-xl-4">
<select className="form-control">
<option>1</option>
<option>2</option>
</select>
<button
onClick={cancelOnClick}
className="btn btn-warning form-control col-5 col-sm-5 col-md-3 col-lg-2 col-xl-2 m-2"
>
Cancel
</button>
<button className="btn btn-success form-control col-5 col-sm-5 col-md-3 col-lg-2 col-xl-2 m-2">
Save
</button>
</div>
</div>
)}
</div>
<hr />
</div>
)
}

state uses with authentication

i'm new in coding and i I still have a problem with if else condition, i have 2 authentication and one back end , one for react native and one for react ,
in Login i want to add is_store , i want to tell the system that if the username & password correct and is_sore = true , make him logged in and if the password right and the username right BUT is_store = false don't logged him in
i'm trying to pass is_store to Login component
i tried if condition but it give me wrong alert
Signup component
class RegistationForm extends Component {
state = {
username: "",
phone_number: "",
password: "",
email: "",
is_store: true <--- i want to pass it to Login
};
componentWillUnmount() {
this.props.errors.length && this.props.resetError();
}
changeHandler = e => {
this.setState({ [e.target.name]: e.target.value });
};
submitHandler = async e => {
e.preventDefault();
this.props.signup(this.state, this.props.history);
};
render() {
return (
<div className="container">
<div
style={{ marginTop: "125px" }}
className="card o-hidden border-0 shadow-lg col-12"
>
<div className="card-body p-0">
<div className="row">
<div className="col-lg-5 d-none d-lg-block bg-register-image col-12" />
<div className="col-lg-7 col-12">
<div className="p-5">
<div className="text-center col-12">
<h1 className="h4 text-gray-900 mb-4 col-12">
إنشاء حساب جديد
</h1>
</div>
<div className="text-center col-12">
{!!this.props.errors.length && (
<div className="text-left alert alert-danger">
{this.props.errors.map(error => (
<li key={error}>{error}</li>
))}
</div>
)}
</div>
<form onSubmit={this.submitHandler}>
<div className="form-group row">
<div className="col-sm-6 mb-3 mb-sm-0">
<Input
name="username"
value={this.state.username}
onChange={this.changeHandler}
className="form-control form-control-user"
placeholder=" السجل التجاري"
required
/>
</div>
<div className="col-sm-6 mb-3 mb-sm-0">
<Input
name="phone_number"
value={this.state.phone_number}
type="tel"
onChange={this.changeHandler}
className="form-control form-control-user"
placeholder="Mobile Ex: 966555555555"
required
pattern="[0-9]{12}"
/>
</div>
<br />
<br />
<div className="col-sm-6 mb-3 mb-sm-0">
<Input
name="password"
value={this.state.password}
onChange={this.changeHandler}
type="password"
className="form-control form-control-user"
placeholder="الرقم السري"
required
/>
</div>
<div className="col-sm-6 mb-3 mb-sm-0 ">
<Input
name="email"
value={this.state.email}
onChange={this.changeHandler}
type="email"
className="form-control form-control-user"
placeholder="الإيميل"
required
/>
</div>
<div className="col-12">
<button
style={{ padding: 9, marginTop: 20 }}
type="submit"
className="btn btn-success col-12 "
>
إنشئ حساب
</button>
</div>
</div>
</form>
<div className="text-center">
<Link to="/login" className="small">
املك حساب من قبل: تسجيل الدخول
</Link>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
Login component
class Login extends Component {
state = {
username: "",
password: "",
is_store: false <-- is here the right place?
};
componentWillUnmount() {
this.props.errors.length && this.props.resetError();
}
changeHandler = e => {
this.setState({ [e.target.name]: e.target.value });
};
submitHandler = async e => {
e.preventDefault();
## here is what i'm trying to do with is_store
if (this.state.is_store === true) {
this.props.login(this.state, this.props.history);
} else {
alert("Wrong");
}
};
render() {
return (
<div className="container">
<div className="row justify-content-center" style={{ marginTop: 125 }}>
<div className="col-xl-10 col-lg-12 col-md-9">
<div className="card o-hidden border-0 shadow-lg my-5">
<div className="card-body p-0">
<div className="row">
<div className="col-lg-6 d-none d-lg-block bg-login-image" />
<div className="col-lg-6">
<div className="p-5">
<div className="text-left">
<h1 className="h4 text-gray-900 mb-4">تسجيل الدخول</h1>
{!!this.props.errors.length && (
<div className="alert alert-danger" role="alert">
{this.props.errors.map(error => (
<li key={error}>{error}</li>
))}
</div>
)}
</div>
<form onSubmit={this.submitHandler}>
<div
className="form-group col-12"
style={{ padding: 0 }}
>
<Input
name="username"
className="form-control form-control-user"
onChange={this.changeHandler}
value={this.state.username}
placeholder="رقم السجل التجاري"
/>
</div>
<div
className="form-group col-12"
style={{ padding: 0 }}
>
<Input
type="password"
className="form-control form-control-user"
name="password"
value={this.state.passsword}
onChange={this.changeHandler}
placeholder="الرقم السري"
/>
</div>
<button
style={{ padding: 9 }}
type="submit"
className="btn btn-primary col-12"
>
دخول
</button>
<hr />
</form>
<hr />
<div className="text-center">
<NavLink to={`/signup`}>إنشاء حساب جديد</NavLink>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
this is authentication actions
export const login = (userData, history) => {
return async dispatch => {
try {
let response = await instance.post("user/login/", userData);
let user = response.data;
setAuthToken(user.token);
let decodedUser = jwt_decode(user.token);
dispatch(setCurrentUser(decodedUser));
history.push("/home");
} catch (error) {
console.log("error", error);
dispatch(setErrors(error.response.data));
}
};
};
thank you
In general, You can pass a state to a child component only. You can not pass a state from a child to its parent component.
In order to pass state to a parent component, you need to store that value. You can do it with Redux. Which stores the values and you can get that value in any component.

In React, using bootstrap modal how to edit and update State?

I have a table that shows a list of projects. When I click on a row to render a Modal, how do I prefill my input fields with data that I clicked on and then edit the fields so the state can be updated with the new data that I provide?
Here's my code breakdown with respective files:
Project.js
const Project = ({ companies, projects }) => {
return(
<div>
<section id={styles.project} className="divider overlay-light" data-bg-img="http://placehold.it/1920x1280">
<div className={`container ${styles.wrapper}`}>
<div className="row">
<div className={`col-md-12 ${styles['proj-header']}`}>
<h2 className="title">Projects</h2>
<button type="button" className={`btn ${styles['btn-project']}`} data-toggle="modal" data-target="#createProject">Create New Project</button>
{
companies.map((company, i) => {
return <CreateProjectModal key={i} company={company} />
})
}
</div>
</div>
<ManageColumns />
<div className="row">
<div className="col-md-12">
<div className={`${styles['table-responsive']} ${styles['dashboard-overview']} tableContainer`}>
<table className={`table table-striped scrollTable`}>
<thead className="fixedHeader">
<tr>
<th>Project Name <i className="fas fa-sort-amount-down"></i></th>
<th>Project Description</th>
<th>Action</th>
</tr>
</thead>
<tbody className="scrollContent">
{
projects.map((project, i) => {
return (
<tr key={i}>
<td>{project.project_name}</td>
<td>{project.description}</td>
<td>
<EditProjectModal projects={projects} />
</td>
</tr>
);
})
}
</tbody>
</table>
</div>
</div>
</div>
</div>
</section>
</div>
)
}
export default Project;
CreateProjectModal.js
class CreateProjectModal extends Component {
constructor(props) {
super(props);
this.state = {
project_name: '',
description: ''
}
}
onProjectNameChange(event) { this.setState({ project_name: event.target.value }); }
onDescriptionChange(event) { this.setState({ description: event.target.value }); }
handleSubmit(company) {
fetch(`http://localhost:5000/companys/${company._id['$oid']}/projects`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
project: {
project_name: this.state.project_name,
description: this.state.description
}
})
})
.then(response => response.json())
.then(data => { return data })
.catch(err => console.log(err));
}
render() {
const { company } = this.props;
return(
<div>
<div id="createProject" className="modal fade" tabIndex="-1" role="dialog">
<div className={`modal-dialog modal-lg ${styles['create-proj-modal']}`}>
<div className="modal-content">
<div className={`modal-header ${styles['create-proj-modal-header']}`}>
<button type="button" className={`close ${styles.closeModal}`} data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h3 className="modal-title" id="myModalLabel2">Create New Project</h3>
</div>
<div className={`modal-body ${styles['proj-modal-body']}`}>
<form>
<div className={`form-group ${styles.formGroup} ${styles.projName}`}>
<label htmlFor="project-name" className="col-form-label">Project Name</label>
<input type="text" className="form-control" id="project-name" name="project_name" onChange={(e) => onProjectNameChange(e, this.state)} />
</div>
<div className={`form-group ${styles.formGroup}`}>
<label htmlFor="description" className="col-form-label">Description</label>
<textarea className="form-control" id="description" rows="4" name="description" onChange={(e) => onDescriptionChange(e, this.state)} ></textarea>
</div>
</form>
</div>
<div className={`modal-footer ${styles.modalFooter}`}>
<button type="button" className={`btn btn-primary text-white ${styles.saveBtn}`} onClick={() => handleSubmit(company)}>Save Project</button>
<button type="button" className={`btn btn-default ${styles.cancelBtn}`} data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default CreateProjectModal;
EditProjectModal.js
class EditProjectModal extends Component {
constructor(props) {
super(props);
this.state = {
project_name: '',
description: ''
}
}
onProjectNameChange(event) { this.setState({ project_name: event.target.value }); }
onDescriptionChange(event) { this.setState({ description: event.target.value }); }
handleSubmit(project) {
fetch(`http://localhost:5000/projects/${project._id['$oid']}`, {
method: 'PUT',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
project: {
project_name: this.state.project_name,
description: this.state.description
}
})
})
.then(response => response.json())
.then(data => { return data })
.catch(err => console.log(err));
}
render() {
const { project } = this.props;
return(
<div className="btn-group">
<NavLink type="button" to="#" className={`${styles['pencil-link']}`} data-toggle="modal" data-target="#editProject">
<i className={`fas fa-pencil-alt ${styles.pencil}`}></i>
</NavLink>
<div id="editProject" className="modal fade" tabIndex="-1" role="dialog">
<div className={`modal-dialog modal-lg ${styles['create-proj-modal']}`}>
<div className="modal-content">
<div className={`modal-header ${styles['create-proj-modal-header']}`}>
<button type="button" className={`close ${styles.closeModal}`} data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h3 className="modal-title" id="myModalLabel2">Edit Project</h3>
</div>
<div className={`modal-body ${styles['proj-modal-body']}`}>
<form>
<div className={`form-group ${styles.formGroup} ${styles.projName}`}>
<label htmlFor="project-name" className="col-form-label">Project Name</label>
<input type="text" className="form-control" id="project-name" name="project_name" onChange={this.onProjectNameChange.bind(this)} />
</div>
<div className={`form-group ${styles.formGroup}`}>
<label htmlFor="description" className="col-form-label">Description</label>
<textarea className="form-control" id="description" rows="4" name="description" onChange={this.onDescriptionChange.bind(this)}></textarea>
</div>
</form>
</div>
<div className={`modal-footer ${styles.modalFooter} ${styles.editModalFooter}`}>
<button type="button" className={`btn btn-default ${styles.cancelBtn}`} data-dismiss="modal">Cancel</button>
<button type="button" className={`btn btn-primary text-white ${styles.saveBtn}`} onClick={(e) => this.handleSubmit(project)}>Save Changes</button>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default EditProjectModal;
First of all you need to pass the current row project details as a props to the EditProjectModal when you are filling the projects table (I named it theProject):
<tbody className="scrollContent">
{
projects.map((project, i) => {
return (
<tr key={i}>
<td>{project.project_name}</td>
<td>{project.description}</td>
<td>
<EditProjectModal projects={projects} theProject={project} />
</td>
</tr>
);
})
}
</tbody>
Then in the EditProjectModal, You can set it in the state like this:
constructor(props) {
super(props);
this.state = {
project_name: this.props.theProject.project_name,
description: this.props.theProject.description
}
}
}
Then you need to set the value of the inputs in the EditProjectModal with the state like this:
<form>
<div className={`form-group ${styles.formGroup} ${styles.projName}`}>
<label htmlFor="project-name" className="col-form-label">Project Name</label>
<input type="text" className="form-control" id="project-name"
name="project_name"
value={this.state.project_name}
onChange={this.onProjectNameChange.bind(this)} />
</div>
<div className={`form-group ${styles.formGroup}`}>
<label htmlFor="description" className="col-form-label">Description</label>
<textarea className="form-control" id="description"
rows="4" name="description"
value={this.state.description}
onChange={this.onDescriptionChange.bind(this)}></textarea>
</div>
</form>
The edit form can be initialized by passing the row details as props to the EditProjectModal and the props can be assigned as state of EditProjectModal for making the handling easy.Then you can give value to the input and textarea using the value attribute.The value attribute can be given the corresponding state.
class EditProjectModal extends Component {
constructor(props) {
super(props);
this.state = {
project_name: '',
description: ''
}
}
ComponentWillMount() {
this.setState(project_name: this.props.project.project_name,description:this.props.project.description)
}
render() {
....//rest of the code
<form>
<div className={`form-group ${styles.formGroup} ${styles.projName}`}>
<label htmlFor="project-name" className="col-form-label">Project Name</label>
<input type="text" className="form-control" id="project-name" name="project_name" onChange={this.onProjectNameChange.bind(this)} value={this.state.project_name}/>
</div>
<div className={`form-group ${styles.formGroup}`}>
<label htmlFor="description" className="col-form-label">Description</label>
<textarea className="form-control" id="description" rows="4" name="description" onChange={this.onDescriptionChange.bind(this)} value={this.state. description}/>
</div>
</form>
}
You need the pass the project as
<tbody className="scrollContent">
{
projects.map((project, i) => {
return (
<tr key={i}>
<td>{project.project_name}</td>
<td>{project.description}</td>
<td>
<EditProjectModal project={project} />
</td>
</tr>
);
})
}
</tbody>

Categories