my question is a little complicated, I am building a trip-related web application where users can book trips. So I have made a function that increases the number of travelers as the user clicks the + sign. when this function is called it changes the state and another function gets triggered that displays the form to fill in the traveler details. Now this form is rendered according to the number of travelers traveling. how can I set that data in an array of objects?
here's a screenshot guide:
I want the data to be in the state like this:
travelersDetail: [{firstName: 'Farrukh', lastName:'Ayaz', address:'...', city:'Lahore'},
{firstName: 'Dwight', lastName:'Schrute', address:'...', city:'Scranton'},
{firstName: 'Micheal', lastName:'Scott', address:'...', city:'Scranton'},]
My code:
// state
state = {
NumOfTravellers : 1,
travelersDetail: [],
trip: null,
}
// the functions that increases the number of travelers
handleClick = (e) =>{
e.preventDefault();
if(e.target.id == 'plus'){
this.setState({NumOfTravellers: this.state.NumOfTravellers + 1 })
}
else if(e.target.id == 'minus'){
this.state.NumOfTravellers > 1 ? this.setState({NumOfTravellers:
this.state.NumOfTravellers - 1 }) : alert("can't be less than that :)")
}
}
// the function that returns the traveler details form, according to the number of travelers traveling.
const numberOfTravelers = () =>{
var travellers = [];
for(let t = 0; t < this.state.NumOfTravellers; t++){
travellers.push(
<div >
<h4> Traveller # {t+1} Details</h4><br/>
<div className="form-row">
<div className="form-group col-md-6">
<label htmlFor="firstName">First Name</label>
<input type="firstName" className="form-control" onChange={this.handleTDChange} id="firstName" placeholder="FirstName" />
</div>
<div className="form-group col-md-6">
<label htmlFor="lastName">Last Name</label>
<input type="lastName" className="form-control" onChange={this.handleTDChange} id="lastName" placeholder="LastName" />
</div>
</div>
<div className="form-group">
<label htmlFor="address">Address</label>
<input type="text" className="form-control" onChange={this.handleTDChange} id="address" placeholder="1234 Main St" />
</div>
<div className="form-group">
<label htmlFor="phoneNumber">Phone Number</label>
<input type="tel" className="form-control" onChange={this.handleTDChange} id="phoneNumber" placeholder="+92..." />
</div>
<div className="form-row">
<div className="form-group col-md-6">
<label htmlFor="city">City</label>
<select onChange={this.handleTDChange} id="city" className="form-control">
<option selected>Choose...</option>
<option>Lahore</option>
<option>Islamabad</option>
<option>Karachi</option>
<option>Rawalpindi</option>
<option>Quetta</option>
<option>Multan</option>
</select>
</div>
<div className="form-group col-md-4">
<label htmlFor="state">State</label>
<select onChange={this.handleTDChange} id="state" className="form-control">
<option selected>Choose...</option>
<option>Pakistan</option>
</select>
</div>
<div className="form-group col-md-2">
<label htmlFor="zip">Zip</label>
<input type="text" className="form-control" onChange={this.handleTDChange} id="zip" />
</div>
</div>
</div>);
}
return travellers
}
I don't completely understand you problem, what I understand is.
There is a controller, Plus and Minus. On click of Plus a new Traveler form has to be added and on click of minus the last Travelers form will be removed. And also the traveler counter is incremented or decremented based on the button click
You would not want 2 variables, 1 to keep track of the number of travelers and other to store the traveler details, you can maintain only 1 variable. Just have traverlerDetails, we can get the number of travelers form the size of the traverlerDeterails array.
// state values
this.state = {
travelersDetail: [],
trip: null,
};
handleClick = (clickEvent) => {
clickEvent.preventDefault();
const travelersDetailCopy = [...this.state.travelersDetail];
if (e.target.id == 'plus') {
travelersDetailCopy.push({
firstName: '', lastName: '', address: '', city: '' // Add empty data
});
} else if (e.target.id == 'minus') {
if (this.state.travelersDetail.length === 1) {
alert("Can't be less than 1");
} else {
travelersDetailCopy.pop();
}
}
this.setState({
travelersDetail: travelersDetailCopy
});
}
const numberOfTraverlers = () => {
return this.state.travelersDetail.map((travelerDetails, index) => {
return (
<div key={index}>
<h4> Traveller # {index + 1} Details</h4><br />
<div className="form-row">
<div className="form-group col-md-6">
<label htmlFor="firstName">First Name</label>
<input type="firstName" className="form-control" onChange={(event) => {this.handleTDChange(event, index, "firstName")}} id="firstName" placeholder="FirstName" />
</div>
<div className="form-group col-md-6">
<label htmlFor="lastName">Last Name</label>
<input type="lastName" className="form-control" onChange={(event) => {this.handleTDChange(event, index, "lastName")}} id="lastName" placeholder="LastName" />
</div>
</div>
<div className="form-group">
<label htmlFor="address">Address</label>
<input type="text" className="form-control" onChange={(event) => {this.handleTDChange(event, index, "address")}} id="address" placeholder="1234 Main St" />
</div>
<div className="form-group">
<label htmlFor="phoneNumber">Phone Number</label>
<input type="tel" className="form-control" onChange={(event) => {this.handleTDChange(event, index, "phoneNumber")}} id="phoneNumber" placeholder="+92..." />
</div>
<div className="form-row">
<div className="form-group col-md-6">
<label htmlFor="city">City</label>
<select onChange={(event) => {this.handleTDChange(event, index, "city")}} id="city" className="form-control">
<option selected>Choose...</option>
<option>Lahore</option>
<option>Islamabad</option>
<option>Karachi</option>
<option>Rawalpindi</option>
<option>Quetta</option>
<option>Multan</option>
</select>
</div>
<div className="form-group col-md-4">
<label htmlFor="state">State</label>
<select onChange={(event) => {this.handleTDChange(event, index, "state")}} id="state" className="form-control">
<option selected>Choose...</option>
<option>Pakistan</option>
</select>
</div>
<div className="form-group col-md-2">
<label htmlFor="zip">Zip</label>
<input type="text" className="form-control" onChange={(event) => {this.handleTDChange(event, index, "zip")}} id="zip" />
</div>
</div>
</div>
)
})
}
handleTDChange(event, index, updateField) {
const arrayCopy = [...this.state.travelersDetail];
arrayCopy[index][updateField] = event.target.value;
this.setState({travelersDetail: arrayCopy});
}
Use this.state.travelersDetail.length to display the number of travelers.
Don't use for-loop, make use of built in functions like forEach, map, filter and other methods.
Update :
To handle onChange events, you can have multiple handleChange event handler.
But if you want to do it in a single, you can pass few additional argument. First being the actual event, second the index of the travelerDetails object, third being the property that needs to be updated.
There is a much better way of doing this, extract the content in side the map and create a separate component. Which would contain the logic related to the component. With this updation and also maintenance of the code is much easier
You should be using the array.push() method detailed in javascript to add an element to an existing array.
Example
const array = [];
array.push({ id: 'someId', name: 'someName' });
See documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push
Related
To introduce myself to React I am developing a small application - it is a 'media bookmark'. For example you really like a chapter from a certain book, so you give the application the name of the book, chapter, that it is a book, a description and a link if applicable.
The error I keep getting is:
Argument of type 'string' is not assignable to parameter of type 'SetStateAction<MediaBookmarkDTO>'
This is my code:
const [newBookmark, setNewBookmark] = useState<MediaBookmarkDTO>({ bookmarkName: '', bookmarkDescription: '', bookmarkType: '', bookmarkChapOrEp: '', bookmarkLink: '' });
And where I try to bind:
<div className="form-group col-md-4">
<label htmlFor="BookmarkName">Name:* </label>
<input type="text" className="form-control" id="BookmarkName" placeholder="Name"
value={newBookmark.bookmarkName} onChange={(e) => setNewBookmark(e.target.value)} />
</div>
Currently you are trying to update newBookmark with a string. Since a string isn't a MediaBookmarkDTO, you get an error. You probably meant to update the name only, which you can do inline like this:
<div className="form-group col-md-4">
<label htmlFor="BookmarkName">Name:* </label>
<input
type="text"
className="form-control"
id="BookmarkName"
placeholder="Name"
value={newBookmark.bookmarkName} onChange={(e) => setNewBookmark({
...newBookmark,
bookmarkName: e.target.value,
})}
/>
</div>
First of all welcome to stack overflow family.
newBookmark variable is MediaBookmarkDTO which is a object, when you try to update directly using setNewBookmark(e.target.value), it is trying to provide string value to newBookmark variable, which is where typescript is complaining.
When you are working with forms, in starting I would recommend to have separate state for each field it will help you understand more, when you got the base, then you can use single variable to store all form state. Below is an example to manage the form using a separate state.
import React, { useState } from 'react'
function BookmarkComponent() {
const [bookmarkName, setNewBookmarkName] = useState<string>('');
const [bookmarkDescription, setBookmarkDescription] = useState<string>('');
const [bookmarkType, setBookmarkType] = useState<string>('');
const [bookmarkChapOrEp, setBookmarkChapOrEp] = useState<string>('');
const [bookmarkLink, setBookmarkLink] = useState<string>('');
return (
<form>
<div className="form-group col-md-4">
<label htmlFor="BookmarkName">Name:* </label>
<input type="text" className="form-control" id="BookmarkName" placeholder="Name"
value={bookmarkName} onChange={(e) => setNewBookmarkName(e.target.value)} />
</div>
<div className="form-group col-md-4">
<label htmlFor="BookmarkDescription">Description:* </label>
<input type="text" className="form-control" id="BookmarkDescription" placeholder="Description"
value={bookmarkDescription} onChange={(e) => setBookmarkDescription(e.target.value)} />
</div>
<div className="form-group col-md-4">
<label htmlFor="BookmarkType">Type:* </label>
<input type="text" className="form-control" id="BookmarkType" placeholder="Type"
value={bookmarkType} onChange={(e) => setBookmarkType(e.target.value)} />
</div>
<div className="form-group col-md-4">
<label htmlFor="BookMarkChapter">Chapter:* </label>
<input type="text" className="form-control" id="BookMarkChapter" placeholder="Chapter"
value={bookmarkChapOrEp} onChange={(e) => setBookmarkChapOrEp(e.target.value)} />
</div>
<div className="form-group col-md-4">
<label htmlFor="BookmarkLink">Link:* </label>
<input type="text" className="form-control" id="BookmarkLink" placeholder="Link"
value={bookmarkLink} onChange={(e) => setBookmarkLink(e.target.value)} />
</div>
</form>
)
}
export default BookmarkComponent
When You get more experience you can use Libraries to manage form they are extremely Helpful when managing complex form, below are libraries I used which works very well
React Hook Form
Formik
I made such a project through context. But I can't save the values of checkbox and select options in memory. All other inputs work correctly. CRUD operations are fine, but when I select and confirm the gender, then when I try to edit the details of that contact, the gender of the contact is not visible. Also, the ``I want to receive information'' button at the bottom does not appear checked.
import React, { useState } from "react";
import { useContext } from "react";
import { GlobalContext } from "../../context/GlobalState";
import { useNavigate } from "react-router-dom";
import { NavLink } from "react-router-dom";
import { v4 as uuidv4 } from 'uuid';
const Form = () => {
const { ADD_CONTACT } = useContext(GlobalContext);
const [contact, setContact] = useState({
id: uuidv4(),
name: "",
surname: "",
fatherName: "",
specialty: "",
email: "",
gender: "",
updatesNotification:''
});
const { name, surname, fatherName, specialty, email } = contact;
let history = useNavigate();
const onSubmit = (e) => {
e.preventDefault();
if (contact) {
ADD_CONTACT(contact);
history("/contacts");
console.log(contact);
}
};
return (
<form onSubmit={onSubmit}>
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">Name</label>
<div class="col-sm-10">
<input
class="form-control"
name="name"
required
value={name}
onChange={(e) =>
setContact({ ...contact, [e.target.name]: e.target.value })
}
/>
</div>
</div>
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">Surname</label>
<div class="col-sm-10">
<input
class="form-control"
name="surname"
required
value={surname}
onChange={(e) =>
setContact({ ...contact, [e.target.name]: e.target.value })
}
/>
</div>
</div>
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">Father Name</label>
<div class="col-sm-10">
<input
class="form-control"
name="fatherName"
required
value={fatherName}
onChange={(e) =>
setContact({ ...contact, [e.target.name]: e.target.value })
}
/>
</div>
</div>
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">Email</label>
<div class="col-sm-10">
<input
class="form-control"
name="email"
required
value={email}
onChange={(e) =>
setContact({ ...contact, [e.target.name]: e.target.value })
}
/>
</div>
</div>
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">Specialty</label>
<div class="col-sm-10">
<input
class="form-control"
name="specialty"
required
value={specialty}
onChange={(e) =>
setContact({ ...contact, [e.target.name]: e.target.value })
}
/>
</div>
</div>
<div className="mb-3 row">
<label class="col-sm-2 col-form-label">Job</label>
<div className="col-sm-10 d-flex justify-content-center align-items-center">
<select class="form-select" aria-label="Default select example">
<option selected>Bakalavr</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
</div>
</div>
<div className="mb-3 row">
<label class="col-sm-2 col-form-label">Gender</label>
<div className="col-sm-10">
<div class="form-check form-check-inline ">
<input
class="form-check-input"
type="radio"
name="gender"
value="male"
onChange={(e) =>
setContact({ ...contact, [e.target.name]: e.target.value })
}
/>
<label class="form-check-label">Kisi</label>
</div>
<div class="form-check form-check-inline">
<input
class="form-check-input"
type="radio"
name="gender"
value="female"
onChange={(e) =>
setContact({ ...contact, [e.target.name]: e.target.value })
}
/>
<label class="form-check-label">Female</label>
</div>
</div>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" />
<label class="form-check-label" for="flexCheckDefault">
I want to be notified of updates
</label>
</div>
<button type="submit" class="btn btn-primary">
Create a new contact
</button>
<NavLink to="/contacts" className="btn btn-danger m-2">
Cancel
</NavLink>
</form>
);
};
export default Form;
import React from "react";
import { NavLink } from "react-router-dom";
import { useContext, useState, useEffect } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { GlobalContext } from "../../context/GlobalState";
const EditContactForm = () => {
const { contacts, UPDATE_CONTACT } = useContext(GlobalContext);
const [selectedContact, setSelectedContact] = useState({
id: "",
name: "",
surname: "",
fatherName: "",
specialty: "",
email: "",
gender: "",
});
const history = useNavigate();
const {id} = useParams();
useEffect(() => {
const userId = id;
const selectedContact = contacts.find((user) => String(user.id) === userId);
if (selectedContact) {
setSelectedContact(selectedContact);
}
}, [id, contacts]);
function onSubmit(e) {
e.preventDefault();
UPDATE_CONTACT(selectedContact);
console.log("new user edited:", selectedContact);
history("/contacts");
}
const handleOnChange = (e) => {
setSelectedContact(selectedContact => ({
...selectedContact,
[e.target.name]: e.target.value
}));
};
return (
<div>
<form onSubmit={onSubmit}>
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">Name</label>
<div class="col-sm-10">
<input
class="form-control"
name="name"
required
value={selectedContact?.name ?? ''}
onChange={handleOnChange}
/>
</div>
</div>
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">Surname</label>
<div class="col-sm-10">
<input
class="form-control"
name="surname"
required
value={selectedContact?.surname ?? ''}
onChange={handleOnChange}
/>
</div>
</div>
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">Father Name</label>
<div class="col-sm-10">
<input
class="form-control"
name="fatherName"
required
value={selectedContact?.fatherName ?? ''}
onChange={handleOnChange}
/>
</div>
</div>
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">Email</label>
<div class="col-sm-10">
<input
class="form-control"
name="email"
required
value={selectedContact?.email ?? ''}
onChange={handleOnChange}
/>
</div>
</div>
<div class="mb-3 row">
<label class="col-sm-2 col-form-label">Specialty</label>
<div class="col-sm-10">
<input
class="form-control"
name="specialty"
required
value={selectedContact?.specialty ?? ''}
onChange={handleOnChange}
/>
</div>
</div>
<div className="mb-3 row">
<label class="col-sm-2 col-form-label">Vezife</label>
<div className="col-sm-10 d-flex justify-content-center align-items-center">
<select class="form-select" aria-label="Default select example">
<option selected>Bakalavr</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
</div>
</div>
<div className="mb-3 row">
<label class="col-sm-2 col-form-label">Gender</label>
<div className="col-sm-10">
<div class="form-check form-check-inline ">
<input
class="form-check-input"
type="radio"
name="gender"
required
value="male"
onChange={handleOnChange}
/>
<label class="form-check-label">Male</label>
</div>
<div class="form-check form-check-inline">
<input
class="form-check-input"
type="radio"
name="gender"
value="female"
onChange={handleOnChange}
/>
<label class="form-check-label">Female</label>
</div>
</div>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" />
<label class="form-check-label" for="flexCheckDefault">
I want to be notified of updates
</label>
</div>
<button type="submit" class="btn btn-primary">
Update a contact
</button>
<NavLink to="/contacts" className="btn btn-danger m-2">
Cancel
</NavLink>
</form>
</div>
);
};
export default EditContactForm;
enter image description here
enter image description here
sandbox: https://codesandbox.io/s/task1-w5zvg4?file=/src/App.js
When working with checkbox you have to look for e.target.checked to access if it is checked or not.
You can try something like this:
<div class="form-check form-check-inline">
<input
class="form-check-input"
type="radio"
name="gender"
id="female"
checked={contact.gender === "female"}
onChange={(e) =>
setContact({ ...contact, [e.target.name]: e.target.checked ? e.target.id : "" })
}
/>
<label htmlFor="female" class="form-check-label">Female</label>
</div>
For the select, you can achieve this like this:
const selectOptions = [
{label: "One", value: 1},
{label: "Two", value: 2},
{label: "Three", value: 3},
]
const Test = () => {
const onChange = (e) => setContact({ ...contact, [e.target.name]: e.target.value })
return <>
<label class="col-sm-2 col-form-label">Job</label>
<div className="col-sm-10 d-flex justify-content-center align-items-center">
<select value={contact.test} onChange={onChange} name="test" class="form-select" aria-label="Default select example">
{selectOptions.map(item => (
<option key={item.value} value={item.value}>{item.label}</option>
))}
</select>
</div>
</>
}
I am using the class component here Consider selecting Yes or No value depending on whether to show or hide the div.
I wanted to do the same thing with multiple div. But here if I am selecting yes then both the div are open. And not close to clicked on no value.
Here is my code:
class PersonalInfo extends Component {
constructor(props) {
super(props);
this.divstatus1 = this.divstatus1.bind(this);
this.divstatus2 = this.divstatus2.bind(this);
this.state = {
value1: 'no',
value2: 'no'
};
}
divstatus1 = (e) => {
this.setState({ value1: e.target.value1 });
}
divstatus2 = (e) => {
this.setState({ value2: e.target.value2 });
}
render() {
return (
<div>
<h3 className="showbase_header">Passport Details</h3>
<div className="form-group">
<label htmlFor="orderby"> Do you have passport ?</label>
<select className="form-control orderby" onChange={this.divstatus1}>
<option value="" selected>Select</option>
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
<br></br>
<div className={this.state.value1} >
<div className="row">
<div className="col-md-6 form-group">
<label htmlFor="name">Passport Number
<span className="required">*</span>
</label>
<input type="text" id="firstname" aria-required="true" size={30} name="firstname" className="form-control" placeholder="" />
</div>
<div className="col-md-6 form-group">
<label htmlFor="name">Place Of Issue
<span className="required">*</span>
</label>
<input type="text" id="lastname" aria-required="true" size={30} name="lastname" className="form-control" placeholder="" />
</div>
</div>
<div className="row">
<div className="col-sm-6 form-group">
<label htmlFor="expirydate">Expiry Date
<span className="required">*</span>
</label>
<input type="date" id="expirydate" aria-required="true" size={30} name="expirydate" className="form-control" placeholder="" />
</div>
<div className="col-sm-6 form-group">
<label htmlFor="issuedate">Issue Date
<span className="required">*</span>
</label>
<input type="date" id="issuedate" aria-required="true" size={30} name="issuedate" className="form-control" placeholder="" />
</div>
</div>
</div>
</div>
<div className="form-group">
<h3 className="showbase_header">Representation</h3>
<select className="form-control orderby" onChange={this.divstatus2}>
<option value="">Select</option>
<option value="yes">Yes</option>
<option value="no">No</option>
</select><br />
<div className={this.state.value2} >
<div class="row">
<div className="col-sm-6 form-group">
<label htmlFor="name">Name
<span className="required">*</span>
</label>
<input type="text" id="name" aria-required="true" size={30} name="name" className="form-control" placeholder="" />
</div>
<div className="col-sm-6 form-group">
<label htmlFor="number">Contact Number
<span className="required">*</span>
</label>
<input type="number" id="name" aria-required="true" size={30} name="number" className="form-control" placeholder="" />
</div>
</div>
</div>
</div>
</div>
);
}
}
export default PersonalInfo;
I have added in main.css
.yes{display: block;}
.no{display: none;}
Can you try this,
divstatus1 = (e) => {
this.setState({ value1: e.target.value });
}
divstatus2 = (e) => {
this.setState({ value2: e.target.value });
}
option does not have an attribute called value1 or value2
I have a form in my react project with few input tags
and select tags. On the browser the inputs are rendering
but the select tags are not rendering. I am using materialize css
for the styling. I inspect the elements, the select element is showing
on the elements inspection pane and there is no console error about it.
What could be the problem and the possible
solution? The codes is as show below with screen shots.
import React, { useState, useEffect, useRef } from 'react';
import { useDispatch } from 'react-redux';
import M from 'materialize-css/dist/js/materialize'
function Register() {
const initialState = {
pin: '',
serial_num: '',
last_name: '',
first_name: '',
date: '',
gender: 'male',
school: '',
class: '',
photo: ''
}
const photoRef = useRef();
const dispatch = useDispatch();
useEffect(() => {
const elems = document.querySelectorAll('.datepicker');
M.Datepicker.init(elems, {
autoClose: true
});
}, []);
const [regState, setRegState] = useState(initialState)
const onChange = e => {
setRegState({ ...regState, [e.target.name]: e.target.value });
}
const onSubmit = e => {
// dispatch();
setRegState({...regState,
photo: photoRef.current.files[0].name
})
console.log(regState)
console.log(photoRef.current.files[0].name);
setRegState({ ...initialState });
e.preventDefault();
}
return (
<div className="row">
<form method='POST'
onSubmit={onSubmit}
className="col s12"
encType="multipart/form-data"
>
<div className="input-field col s12">
<input id="serial_num" type="text"
className="validate" name="serial_num"
min="13" max="17" onChange={onChange} required
value={regState.serial_num}
/>
<label htmlFor="serial_num">Serial Number</label>
</div>
<div className="input-field col s12">
<input id="pin" type="password"
className="validate" name="pin"
min="10" max="15" onChange={onChange} required
value={regState.pin}
/>
<label htmlFor="pin">Pin</label>
</div>
<div className="input-field col s12">
<input id="last_name" type="text"
className="validate" name="last_name"
onChange={onChange} required
value={regState.last_name}
/>
<label htmlFor="last_name">Last Name</label>
</div>
<div className="input-field col s12">
<input id="first_name" type="text"
className="validate" name="first_name"
onChange={onChange} required
value={regState.first_name}
/>
<label htmlFor="first_name">First Name</label>
</div>
<div className="input-field col s12">
<input id="date" type="text"
className="validate datepicker" name="date"
onChange={onChange} required
value={regState.date}
/>
<label htmlFor="date">Date of Birth</label>
</div>
<div className="input-field col s12">
<label>
<input name="gender" type="radio" checked value='male' onChange={onChange} />
<span>Male</span>
</label>
</div>
<div className="input-field col s12">
<label>
<input name="gender" type="radio" value='female' onChange={onChange} />
<span>Female</span>
</label>
</div>
<div className="input-field col s12">
<select name='school' id="school" value={regState.school} onChange={onChange} >
<option value="" >Select School</option>
<option value="nursery" >Nursery School</option>
<option value="primary" >Primary School</option>
<option value="secondary" >Secondary School</option>
</select>
<label htmlFor="school">Select School</label>
</div>
<div className="input-field col s12">
<select name='class' id="class" value={regState.class} onChange={onChange} >
<option value="" >Select Class</option>
</select>
<label htmlFor="class">Select Class</label>
</div>
<div className="input-field col s12">
<input id="photo" type="file"
className="validate" name="photo"
ref={photoRef}
/>
<label htmlFor="photo">Photo</label>
</div>
<button className="btn waves-effect waves-light" type="submit" name="action">Submit
<i className="material-icons right">send</i>
</button>
</form>
</div>
)
}
Select needs to be initialized - after it's been added to the DOM, and every subsequent time it is rendered:
var elems = document.querySelectorAll('select');
var instances = M.FormSelect.init(elems);
FYI, Materialize hides the native select (display:none) and only generates the new select (actually a dropdown triggered by a text input) when the init runs. You can also use .browser-default on the select and bypass the init and the materialize styling.
I created laravel project with the reactjs framework and I'm new for this framework. I have problem and why It happens every time i submit the form.
Goal: users can register through online
Problem:
Why it happens when i submit the button the input value of user shown in the url link?
The data that I input is not inserted to the database.
Code:
constructor() {
super();
this.state = {
f_name:'',
l_name:'',
m_name:'',
email:'',
home_num:'',
contact_num:'',
Job_name:[],
employ_status:'',
employ_relocate:'',
employ_start_date:'',
employ_file:''
}
this.handleSubmit = this.handleSubmit.bind(this);
this.handle_fname = this.handle_fname.bind(this);
this.handle_lname = this.handle_lname.bind(this);
this.handle_mname = this.handle_mname.bind(this);
this.handle_email = this.handle_email.bind(this);
this.handle_homenum = this.handle_homenum.bind(this);
this.handle_contactnum = this.handle_contactnum.bind(this);
this.handle_employ_status = this.handle_employ_status.bind(this);
this.handle_employ_relocate = this.handle_employ_relocate.bind(this);
this.handle_employ_start_date = this.handle_employ_start_date.bind(this);
this.handle_employ_file = this.handle_employ_file.bind(this);
}
componentDidMount() {
const id = this.props.match.params.id;
axios.get('/api/online_application_job_title/' +id).then(response => {
this.setState({
Job_name:response.data
})
})
}
handleSubmit(e)
{
const data = {
firstname: this.state.f_name,
lastname : this.state.l_name,
middlename : this.state.m_name,
email : this.state.email,
home_number : this.state.home_num,
contact_num : this.state.contact_num,
job : this.state.Job_name[0].position_name,
employ_status : this.state.employ_status,
employ_relocate : this.state.employ_relocate,
employ_start_date : this.state.employ_start_date,
employ_file : this.state.employ_file
}
axios.post('/api/save_application',data).then(response => {
console.log(response);
}).catch(error => console.log(error));
}
handle_fname(e)
{
this.setState({
f_name:e.target.value,
})
}
handle_lname(e){
this.setState({
l_name:e.target.value,
})
}
handle_mname(e){
this.setState({
m_name:e.target.value,
})
}
handle_email(e){
this.setState({
email:e.target.value,
})
}
handle_homenum(e){
this.setState({
home_num:e.target.value
})
}
handle_contactnum(e){
this.setState({
contact_num:e.target.value
})
}
handle_employ_status(e){
this.setState({
employ_status:e.target.value
});
}
handle_employ_relocate(e){
this.setState({
employ_relocate:e.target.value,
})
}
handle_employ_start_date(e){
this.setState({
employ_start_date:e.target.value,
})
}
handle_employ_file(e){
this.setState({
employ_file: e.target.files[0].extension
})
}
renderName() {
return (
this.state.Job_name.map(name => (
<input placeholder="" value={name.position_name} type="text" className="form-control"/>
))
)
}
render() {
return (
<div>
<div className="header">
<div className="jumbotron">
<h1>Online Application</h1>
</div>
</div>
<form onSubmit={this.handleSubmit}>
<div className="container">
<h5><b>Personal Info</b></h5>
<br/>
<div className="row">
<div className="col-md-6">
<input
placeholder="First Name*"
value={this.state.f_name}
onChange={this.handle_fname}
className="form-control"/>
</div>
<div className="col-md-6">
<input
placeholder="Last Name*"
value={this.state.l_name}
onChange={this.handle_lname}
className="form-control"/>
</div>
</div>
<br/>
<div className="row">
<div className="col-md-6">
<input
placeholder="Middle Name*"
value={this.state.m_name}
onChange={this.handle_mname}
className="form-control"/>
</div>
<div className="col-md-6">
<input
placeholder="Email Address*"
type="email"
value={this.state.email}
onChange={this.handle_email}
className="form-control"/>
</div>
</div>
<br/>
<div className="row">
<div className="col-md-6">
<input
placeholder="Home Number*"
type="number"
value={this.state.home_num}
onChange={this.handle_homenum}
className="form-control"/>
</div>
<div className="col-md-6">
<input
placeholder="Contact Number*"
type="number"
value={this.state.contact_num}
onChange={this.handle_contactnum}
className="form-control"/>
</div>
</div>
<br/><br/>
<h5><b>Employment Application</b></h5>
<br/>
<div className="row">
<div className="col-md-6">
<p>Position Applying For</p>
{this.renderName()}
</div>
<div className="col-md-6">
</div>
</div>
<br/><br/>
<div className="row">
<div className="col-md-6">
<p>1. What is your current employment status?</p>
<div className="form-check-inline">
<label className="form-check-label">
<input
type="radio"
className="form-check-input"
name="employmentstatus"
onChange={this.handle_employ_status}
defaultChecked={false}
value="Unemployed"/>Unemployed
</label>
</div>
<div className="form-check-inline">
<label className="form-check-label">
<input
type="radio"
className="form-check-input"
name="employmentstatus"
onChange={this.handle_employ_status}
defaultChecked={false}
value="Employed"/>Employed
</label>
</div>
<div className="form-check-inline disabled">
<label className="form-check-label">
<input
type="radio"
className="form-check-input"
name="employmentstatus"
onChange={this.handle_employ_status}
defaultChecked={false}
value="Self-Employed"/>Self-Employed
</label>
</div>
<div className="form-check-inline disabled">
<label className="form-check-label">
<input
type="radio"
className="form-check-input"
name="employmentstatus"
onChange={this.handle_employ_status}
defaultChecked={false}
value="Student"/>Student
</label>
</div>
</div>
<div className="col-md-6"></div>
</div>
<br/>
<div className="row">
<div className="col-md-6">
<p>2. Are you willing to relocate?</p>
<div className="form-check-inline">
<label className="form-check-label">
<input type="radio"
name="relocate"
onChange={this.handle_employ_relocate}
className="form-check-input"
value="Yes"/>Yes
</label>
</div>
<div className="form-check-inline">
<label className="form-check-label">
<input type="radio"
name="relocate"
onChange={this.handle_employ_relocate}
className="form-check-input"
value="No"/>No
</label>
</div>
</div>
<div className="col-md-6"></div>
</div>
<br/>
<div className="row">
<div className="col-md-6">
<p>3. When is your available start date?</p>
<input
name="startdate"
type="date"
onChange={this.handle_employ_start_date}
value={this.state.employ_start_date}
required=""
className="form-control"/>
</div>
<div className="col-md-6"></div>
</div>
<br/>
<div className="row">
<div className="col-md-6">
<p>4. Kindly attach a copy of your resume (PDF,docx files only).</p>
<div className="custom-file">
<input
type="file"
name="file"
accept="application/msword,application/pdf"
onChange={this.handle_employ_file}
className="custom-file-input"
id="inputGroupFile04"/>
<label className="custom-file-label" htmlFor="inputGroupFile04">Choose file</label>
</div>
</div>
<div className="col-md-6"></div>
</div>
<br/>
<div className="row">
<div className="col-md-6">
<input
className="btn btn-outline-primary btn-large form-control col-md-5"
type="submit"
value="Send Application"/>
</div>
<div className="col-md-6"></div>
</div>
</div>
</form>
</div>
)
}
Controller:
public function save_application(Request $request)
{
$firstname = $request->get('firstname');
$lastname = $request->get('lastname');
$middlename = $request->get('middlename');
$email = $request->get('email');
$home_number = $request->get('home_number');
$contact_num = $request->get('contact_num');
$job = $request->get('job');
$employ_status = $request->get('employ_status');
$employ_relocate = $request->get('employ_relocate');
$employ_start_date = $request->get('employ_start_date');
$employ_file = $request->get('employ_file');
$now = new DateTime();
DB::insert('INSERT INTO onlineapplication
(position_name,firstname,middlename,lastname,email,homenumber,phonenumber,employmentstatus,relocate,starting_date,destination,file_img_name,Status)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)',[
$firstname,
$lastname,
$middlename,
$email,
$home_number,
$contact_num,
$job,
$employ_status,
$employ_relocate,
$employ_start_date,
$employ_file
]);
return response()->json('Successfully inserted');
}
When form tag is used, the submit will trigger the default behaviour that is based on the method provided and the action url.
as in your example you are handling the data explicitly you should prevent the default behaviour.
add the below code in handle submit
handleSubmit(e) {
e.preventDefault();
...
...
}
this will prevent the default behaviour.
Improvement for state update:
you don't need individual functions to update the input value to state this can be combined in one function.
to combine, provide the input name same as state name.
this.state ={
"f_name": '',
"l_name": '',
...
}
<input name="f_name" ... onChange={this.handleInputChange}/>
<input name="l_name" .. onChange={this.handleInputChange}/>
handleInputChange(e){
let target = e.target;
let name = target.name;
let value = target.value
this.setState({[name]: value})
}
for more info refer this link.
First, I just want to introduce to you to the arrow function in JavaScript (ES6). Declaring private methods like this:
handle_fname = (e) =>
{
this.setState({
f_name:e.target.value,
})
}
will save you time from unnecessary binding in the constructor.
Regarding your question, you missed to show the content of your this.handleSubmit(). Without this, I can assume that the form submit fired a get call since you failed to put method attribute in your <form/> tag, and without indicating your method attribute will result to default get method. Get method when used, data submitted will be visible in the page address field of your browser.
EDIT
You already added your handleSubmit() in your question, and it looks okay. If data is still shown in the address field of your browser, try adding method="post" in your form tag like this:
<form onSubmit={this.handleSubmit} method="post">