I'm making a simple resume portal and I have a textarea(1), in which user can write his/her work experience. To add more than one work experience I have set a button(Add) which basically will add a new textarea(similar to textarea(1) but without label) just below the textarea(1) and so on. This all should be done when button(Add) is clicked.
If I am able to add my code in a child component that would solve my problem I think.
Here's below what I tried:
Child component ( src -> Routes -> UserForm -> Components -> UserDetails -> index.js )
import React from 'react'
import './style.scss';
import { Row, Col } from 'react-bootstrap'
const UserDetails = () => {
return (
<>
<div className='UserDetails'>
<Row>
<Col lg='6'>
<div className='persnlInfo'>
<h4>
Personal Information
</h4>
<p>Your Name</p>
<input type="text" placeholder="Enter here" />
<p>Your Contact</p>
<input type="text" placeholder="Enter here" />
<p>Your Address</p>
<textarea className='formAddress' rows="5" cols="10" placeholder="Enter here" />
<p id='impLinks'>Important Links</p>
<p>Facebook</p>
<input type="text" placeholder="Enter here" />
<p>Instagram</p>
<input type="text" placeholder="Enter here" />
<p>Linkedin</p>
<input type="text" placeholder="Enter here" />
</div>
</Col>
<Col lg='6'>
<h4>
Professional Information
</h4>
<p>Objective</p>
<textarea className='formObjective' rows="5" cols="10" placeholder="Enter here" />
<p>Work Experience</p>
<textarea className='formObjective' rows="3" cols="10" placeholder="Enter here" />
<div className='addButton'>
<input type='button' id='addWrkExp' value='Add' />
</div>
</Col>
</Row>
</div>
</>
)
}
export default UserDetails;
Parent component ( src -> Routes -> UserForm -> index.js )
import React from 'react'
import Pages from '../../Components/HOC/Page/index'
import UserDetails from '../UserForm/Components/UserDetails/index'
class UserForm extends React.Component{
render() {
return(
<>
<Pages
showHeader
showFooter
>
<UserDetails />
</Pages>
</>
);
}
}
export default UserForm;
Output:
To obtain the said above, I've searched up on this but not getting What and Where to put logic/code exactly. If I'm not wrong this can be done using state , props , onClick() and/or something related.
I hope this is enough from my side to understand the problem. Thanks in advance for your help.
You can use a useState for the number of textareas on your page and then when button(add) gets clicked, that state gets increased by one,
This is your Child component ( src -> Routes -> UserForm -> Components -> UserDetails -> index.js )
import React, { useState } from 'react'
import './style.scss';
import { Row, Col } from 'react-bootstrap'
const UserDetails = () => {
const [ workXPs, setWorkXPs ] = useState(1);
return (
<>
<div className='UserDetails'>
<Row>
<Col lg='6'>
<div className='persnlInfo'>
<h4>
Personal Information
</h4>
<p>Your Name</p>
<input type="text" placeholder="Enter here" />
<p>Your Contact</p>
<input type="text" placeholder="Enter here" />
<p>Your Address</p>
<textarea className='formAddress' rows="5" cols="10" placeholder="Enter here" />
<p id='impLinks'>Important Links</p>
<p>Facebook</p>
<input type="text" placeholder="Enter here" />
<p>Instagram</p>
<input type="text" placeholder="Enter here" />
<p>Linkedin</p>
<input type="text" placeholder="Enter here" />
</div>
</Col>
<Col lg='6'>
<h4>
Professional Information
</h4>
<p>Objective</p>
<textarea className='formObjective' rows="5" cols="10" placeholder="Enter here" />
<p>Work Experience</p>
{[...Array(workXPs).keys()].map((workXP, i) => {
return <textarea key={i} className='formObjective' rows="3" cols="10" placeholder="Enter here" />;
})}
<div className='addButton'>
<input type='button' id='addWrkExp' value='Add' onClick={() => setWorkXPs(prev => (prev + 1))} />
</div>
</Col>
</Row>
</div>
</>
)
}
export default UserDetails;
if you wanna do more advanced and add remove buttons, check this: https://www.educative.io/blog/react-hooks-tutorial-todo-list
hope this helps 🙂
You could just make a state and change the state on the button click.
Then change the style according to the state.
Parent Component
import React from "react";
import Pages from "../../Components/HOC/Page/index";
import UserDetails from "../UserForm/Components/UserDetails/index";
class UserForm extends React.Component {
state = {
textAreas: [{ text: "" }]
};
addTextArea = () => {
let updatedTextArea = [...this.state.textAreas];
updatedTextArea.push({ text: "" });
this.setState({ textAreas: updatedTextArea });
};
render() {
return (
<>
<Pages showHeader showFooter>
<UserDetails textAreas={this.state.textAreas} clicked={this.addTextArea} />
</Pages>
</>
);
}
}
export default UserForm;
i changed <UserDetails textAreas={textAreas} clicked={this.addTextArea} /> to <UserDetails textAreas={this.state.textAreas} clicked={this.addTextArea} />
in the UserForm component
child Component
import React from 'react'
import './style.scss';
import { Row, Col } from 'react-bootstrap'
const UserDetails = (props) => {
const {textAreas, clicked} = props
return (
<>
<div className='UserDetails'>
<Row>
<Col lg='6'>
<div className='persnlInfo'>
<h4>
Personal Information
</h4>
<p>Your Name</p>
<input type="text" placeholder="Enter here" />
<p>Your Contact</p>
<input type="text" placeholder="Enter here" />
<p>Your Address</p>
<textarea className='formAddress' rows="5" cols="10" placeholder="Enter here" />
<p id='impLinks'>Important Links</p>
<p>Facebook</p>
<input type="text" placeholder="Enter here" />
<p>Instagram</p>
<input type="text" placeholder="Enter here" />
<p>Linkedin</p>
<input type="text" placeholder="Enter here" />
</div>
</Col>
<Col lg='6'>
<h4>
Professional Information
</h4>
<p>Objective</p>
<textarea className='formObjective' rows="5"
cols="10" placeholder="Enter here" />
<p>Work Experience</p>
{textAreas.map(item => (
<textarea className='formObjective' value=
{item.value} rows="3" cols="10" placeholder="Enter
here" />
)) }
<div className='addButton' onClick={clicked}>
<input type='button' id='addWrkExp' value='Add' />
</div>
</Col>
</Row>
</div>
</>
)
}
export default UserDetails;
Related
So I have a regular page, I am working with next js. It looks like this:
"use client"
import SubjectInput from "../../../../components/subjectsInput"
export default function Page()
{
let inputs = []
for (let i = 0; i < numberOfInputsGiven; i++) {
inputs.push(<SubjectInput key={i}/>)
}
return(
<>
<form>
<>
{inputs}
</>
<button type="submit">OK</button>
</form>
</>
)
}
I use a component called "SubjectInput", to generate the input fields I need. Now, my question is, how can I access the value of the inputs that are in SubjectInput? Here is what SubjectInput looks like:
export default function SubjectInput(){
return(
<div>
<div>
<label>Name</label>
<input type="text" placeholder="Enter subject's name" required />
</div>
<div>
<label>From</label>
<input type="time" placeholder="Enter subject's starting time" required />
</div>
<div>
<label>To</label>
<input type="time" placeholder="Enter subject's ending time" required />
</div>
</div>
)
}
I would create a component that just holds one label and input, import it into the main page and change the values through props.
Main page
import Input from "./components/Input";
function App() {
return (
<div className="App">
<form>
<Input label="my text" type="text" value="hello" />
<Input label="my number" type="number" value="123" />
<Input type="submit" />
</form>
</div>
);
}
export default App;
Input component
import React from "react";
const Input = (props) => {
return (
<div>
<label>{props.label}</label>
<input type={props.type} value={props.value} />
</div>
);
};
export default Input;
I am trying to build a table-like structure in which I want to add rows dynamically. Here is my code:
import { React, useState } from 'react';
function Table() {
const [add, setAdd] = useState(false);
return (
<div>
<div className="headings">
<p>Item Description</p>
<p>Quantity</p>
<p>Rate</p>
<p>Amount</p>
</div>
<div className="rows">
<input placeholder="Item Description" type="text" />
<input placeholder="Quantity" type="number" />
<input placeholder="Price per piece" type="number" />
<input placeholder="Amount" type="number" />
</div>
{
add ?
<div className="rows" >
<input placeholder="Item Description" type="text" />
<input placeholder="Quantity" type="number" />
<input placeholder="Price per piece" type="number" />
<input placeholder="Amount" type="number" />
</div>
:
<div></div>
}
<button className="add" onClick={()=>setAdd(true)}>Add another line item</button>
</div>
)
}
export default Table;
I have tried adding rows using the button but I am able to add only a single row. The state changes to true so can I reset the state or should I use any other method for adding rows?
You need to set a counter in order to track how many rows you have, and preferably pass it on to another component.
This is not a complete example, neither beautiful one, but the essence is there:
import { React, useState } from "react";
function Rows({ numberOfRows }) {
return [...Array(numberOfRows)].map((element, index) => (
<div key={index}>{`Row Number ${index}`}</div>
));
}
function Table() {
const [numberOfRows, setNumberOfRows] = useState(0);
const addRow = () => {
setNumberOfRows((prev) => prev + 1);
};
const deleteRow = () => {
if (numberOfRows > 0) {
setNumberOfRows((prev) => prev - 1);
}
};
return (
<div>
<div className="headings">
<p>Item Description</p>
<p>Quantity</p>
<p>Rate</p>
<p>Amount</p>
</div>
<Rows numberOfRows={numberOfRows} />
<button className="add" onClick={addRow}>
Add row
</button>
<button className="delete" onClick={deleteRow}>
Delete row
</button>
</div>
);
}
export default Table;
You could keep the lines in state:
import { React, useState } from 'react';
function Table() {
const [addedLines, setAddedLines] = useState([<div key={1} className="rows">
<input placeholder="Item Description" type="text" />
<input placeholder="Quantity" type="number" />
<input placeholder="Price per piece" type="number" />
<input placeholder="Amount" type="number" />
</div>]);
const addLine = () => {
const newLine = (<div key={ addedLines.length + 1 } className="rows" >
<input placeholder="Item Description" type="text" />
<input placeholder="Quantity" type="number" />
<input placeholder="Price per piece" type="number" />
<input placeholder="Amount" type="number" />
</div>)
let a = []
addedLines.forEach((x)=>a.push(x))
a.push(newLine)
setAddedLines(a)
}
return (
<div>
<div className="headings">
<p>Item Description</p>
<p>Quantity</p>
<p>Rate</p>
<p>Amount</p>
</div>
{ addedLines}
<button className="add" onClick={addLine}>Add another line item</button>
</div>
)
}
export default Table;
Codepen: https://codepen.io/guilhermebl/pen/vYxvBWE
Child component renders even though props are not altered of it.
Following is the parent component
import Child from "./Child";
function Parent({
selected,
show,
setShow,
}) {
const [isRunNow, setIsRunNow] = useState(true);
const [isNotifyMe, setIsNotifyMe] = useState(false);
const handleNotify = useCallback(() => {
setIsNotifyMe(!isNotifyMe);
}, [isNotifyMe]);
const handleSchedule = useCallback(() => {
setIsRunNow(!isRunNow);
}, [isRunNow]);
const WindowForm = () => {
return (
<div>
<Row>
<Col span={12}>
<label className={styles.labelWeight}> Name : </label>
<input
type="text"
value={selected.name}
readOnly={true}
className={styles.input}
/>
<br></br>
<br></br>
<label className={styles.labelWeight}>Description : </label>
<input
type="text"
value={selected.description}
readOnly={true}
className={styles.input}
></input>
<br></br>
<br></br>
<input
type="checkbox"
name="runImm"
id="runImm"
checked={isRunNow}
onChange={handleSchedule}
></input>
<label> Schedule as soon as possible</label>
</Col>
<Col span={12}>
<input
type="checkbox"
name="notifyProcess"
id="notifyProcess"
checked={isNotifyMe}
onChange={handleNotify}
></input>
<label> Notify me when this process ends</label>
<br></br>
<br></br>
<label>Submission Notes : </label>
<textarea
name="notes"
id="notes"
rows="4"
cols="50"
disabled={!isNotifyMe}
></textarea>
</Col>
</Row>
<Row>
<Col span={24}>
<Child isRunNow={isRunNow} />
</Col>
</Row>
</div>
);
};
return (
<Modal
visible={show}
width={800}
centered
maskClosable={false}
onCancel={() => setShow(false)}
title="JKM"
>
<WindowForm />
</Modal>
);
}
Child component is as follows:
import Uploader from "./Uploader";
import Downloader from "./Downloader";
const { TabPane } = Tabs;
const areEqual = (prevProps, nextProps) => {
console.log("passed here"); // THIS IS NEVER LOGGED!!
return true;
};
function Child({ isRunNow }) {
console.log(
`Rendering Childe component...isRunNow value : ${isRunNow}`
);
return (
<div>
<Tabs defaultActiveKey="ka">
<TabPane tab="ka" key="ka">
Panel
</TabPane>
<TabPane tab="sa" key="sa" disabled={isRunNow}>
<Downloader />
</TabPane>
<TabPane tab="da" key="da">
<Uploader />
</TabPane>
</Tabs>
</div>
);
}
export default React.memo(Child, areEqual);
When I check or uncheck check box Notify me, the child component Child re-renders every time. It seems props are not equal and hence its re-rending. I could not figure out where its going wrong.
Please suggest where i m doing wrong.
I suggest to you to separate the WindowForm to a component it's seems that this is the problem.
when I use it as a component the memo start to work
I think is due to this is a function that return component so it's render it no matter what.
the solution:
move WindowForm out side of the component and create a new one with it and then call it and it will work fine
const WindowForm = () => {
return (
<div>
<Row>
<Col span={12}>
<label className={styles.labelWeight}> Name : </label>
<input
type="text"
value={selected.name}
readOnly={true}
className={styles.input}
/>
<br></br>
<br></br>
<label className={styles.labelWeight}>Description : </label>
<input
type="text"
value={selected.description}
readOnly={true}
className={styles.input}
></input>
<br></br>
<br></br>
<input
type="checkbox"
name="runImm"
id="runImm"
checked={isRunNow}
onChange={handleSchedule}
></input>
<label> Schedule as soon as possible</label>
</Col>
<Col span={12}>
<input
type="checkbox"
name="notifyProcess"
id="notifyProcess"
checked={isNotifyMe}
onChange={handleNotify}
></input>
<label> Notify me when this process ends</label>
<br></br>
<br></br>
<label>Submission Notes : </label>
<textarea
name="notes"
id="notes"
rows="4"
cols="50"
disabled={!isNotifyMe}
></textarea>
</Col>
</Row>
<Row>
<Col span={24}>
<Child isRunNow={isRunNow} />
</Col>
</Row>
</div>
);
};
this component and his state to a new component and everything will start to work
What is the best (and simplest) way to require inputs (name, email, content etc.) in React.js. I have searched for quite a while but there seems to be so many varying no-so-clear ways to do this. Ideally I want the inputs user_name, user_email and message to be require in order for the form to be sent successfully. Any help would be appreciated.
import React from 'react';
import { MDBContainer, MDBRow, MDBCol, MDBBtn, MDBIcon } from 'mdbreact';
import NavBar from "./NavBar";
import Footer from "./Footer";
import emailjs from 'emailjs-com';
import{ init } from 'emailjs-com';
function Contact() {
function sendEmail(e) {
e.preventDefault();
emailjs.sendForm('hidden', 'hidden', e.target, 'hidden')
.then((result) => {
alert("Great, your request has been sent!");
}, (error) => {
alert("Oops, something went wrong. Please try again")
});
e.target.reset();
}
return (
<div>
<NavBar />
<br />
<br />
<br />
<br />
<br />
<MDBContainer>
<MDBRow className = "formcontainer">
<MDBCol md="6">
<form onSubmit={sendEmail}>
<p className="h4 text-center mb-4">Fill in the information below to contact me!</p>
<br />
<label htmlFor="defaultFormContactNameEx" className="grey-text" > Your name </label>
<input type="text" id="defaultFormContactNameEx" className="form-control" name="user_name" />
<br />
<label htmlFor="defaultFormContactEmailEx" className="grey-text"> Your email </label>
<input type="email" id="defaultFormContactEmailEx" className="form-control" name="user_email"/>
<br />
<label htmlFor="defaultFormContactSubjectEx" className="grey-text"> Subject</label>
<input type="text" id="defaultFormContactSubjectEx" className="form-control" name="user_subject" />
<br />
<label htmlFor="defaultFormContactMessageEx" className="grey-text"> Your message </label>
<textarea type="text" id="defaultFormContactMessageEx" className="form-control" rows="7" name="message"/>
<div className="text-center mt-4">
<MDBBtn color="warning" outline type="submit">
Send
<MDBIcon far icon="paper-plane" className="ml-2" />
</MDBBtn>
</div>
</form>
</MDBCol>
</MDBRow>
</MDBContainer>
<br />
<br />
<Footer />
</div>
);
};
export default Contact;
The easier way to do that is using the required attribute in each of the form's elements.
i.e:
<input required type="email" id="defaultFormContactEmailEx" className="form-control" name="user_email"/>
You can absolutely check if all inputs are not empty when submiting the form too
More info about the required attribute here
import React from 'react';
import { Link } from 'react-router';
import { Field } from 'redux-form';
import BaseForm from '..//BaseForm';
export default class XXXXXXX extends BaseForm {
componentWillMount() {
this.props.retrieveAcademies();
}
render() {
const {
handleSubmit,
formatGraduationDate,
pristine,
submitting,
infoError,
acadamyId
} = this.props;
return (
<div className="col-md-8 col-lg-8 mscs-text">
<div>
<h1 className="mscs-head">Self Registration </h1> <hr />
<form onSubmit={handleSubmit(this.props.startRegistrationProcess.bind(this))} className="registration-step1Class">
<div className="form-section">
<label htmlFor="firstName">First Name:</label>
<Field name="firstName" component={this.renderInputield} label="Enter first Name:" />
</div>
<div className="form-section">
<label htmlFor="lastName">Last Name:</label>
<Field name="lastName" component={this.renderInputield} label="Enter last Name:" />
</div>
<div id="datetimepicker2" className="form-section">
<label htmlFor="dob">Date of Birth:</label>
<Field name="dob" component={this.renderReactDatePicker} type="text" />
</div>
<div className="form-section">
<label htmlFor="maritimeAcadamy">Maritime Academy:</label>
{this.renderAcademiesSelection(acadamyId)}
</div>
<div className="form-section">
<label htmlFor="Yearpassed">Year Passed:</label>
<Field name="passedYear"
component={this.renderReactDatePicker}
type="text"
formatDate={formatGraduationDate}
/>
</div>
<br />
<div className="form-section">
<label htmlFor="CustomerNumber">Customer ID:</label>
<Field name="CustomerNumber" component={this.renderInputield} type="text" label="Enter Customer ID:" />
</div>
<div className="error validation-error">
{infoError && infoError.error} <br />
</div>
<input type="submit" className="btn btn-success" value="Next" />
<input type="reset" className="btn btn-default" value="Cancel" />
</form>
</div>
</div>
);
}
renderAcademiesSelection(acadamyId) {
return (
<div>
<select className="form-control" {...acadamyId}>
<option key={0} value={''}>{'Select your academy'}</option>
{
this.props.academies && this.props.academies.map(function (item, index) {
return (
<option key={item.Id} value={item.Id}>{item.Name}</option>
);
})
}
</select>
</div>
);
}
}
This is the component. Below is the container. The code has some textboxes and dropdowns and calendar controls.
Container :
function mapStateToProps(state, ownProps) {
return {
academies: state.academies.academies,
infoError: state.signUp.error
};
}
const mapDispatchToProps = (dispatch, ownProps) => {
return {
retrieveAcademies: () => {
dispatch(retrieveAcademies());
},
startRegistrationProcess: dispatchGenerateRegistrationToken.bind(this),
nextPage: ownProps.nextPage,
}
}
The above code samples are my react component and container. When I am clicking on the Next button it is not taking me to the next step and it is not showing any type of error in the console. I don't know where exactly the mistake is. I can't debug since the console is not giving any type of error. Any help is appreciated here.