So I am trying to populate a form with data from my server. The server is returning just fine. All strings. I want each form field to be populated with the current details from the database.
I tried the following:
setting each state function in useEffect, but this wouldn't allow me
to change form data
setting a default value but this only works for one instance of the
form and then changes back
function Dashboard(props) {
const { classes } = props;
let user = firebase.getCurrentUser();
let id = user.uid;
const [profile, setProfileData] = useState('');
useEffect( () => {
axios.get('https://www.memento-wedding.com/user/' + id)
.then(response => {
setProfileData(response.data);
})
console.log(profile.gender);
});
const [firstName, setFirstName] = useState('')
const [lastName, setLastName] = useState('');
const [date, setDate] = useState('');
const [gender, setGender] = useState();
return (
<div className="form">
<h1 className="white center">Welcome, {firebase.getCurrentUsername()}!</h1>
<h1 className="white center">Create a Profile</h1>
<Form onSubmit={e => e.preventDefault() && false}>
<Row form>
<Label for="firstName" sm={3} className="white right">First Name</Label>
<Col sm={6}>
<Input type="text" name="firstName" id="name" value={firstName} onChange={e=>setFirstName(e.target.value)}/>
</Col>
<Col sm={1}></Col>
</Row>
<br></br>
<Row form>
<Label for="firstName" sm={3} className="white right">Last Name</Label>
<Col sm={6}>
<Input type="text" name="firstName" id="name" value={lastName} onChange={e=>setLastName(e.target.value)}/>
</Col>
<Col sm={1}></Col>
</Row>
<br></br>
<Row form>
<Label for="email" sm={3} className="white right">Email</Label>
<Col sm={6}>
<Input type="email" name="email" id="email" disabled value={profile.email}/>
</Col>
</Row>
<br></br>
<Row form>
<Label for="birthday" sm={3} className="white right">Birthday</Label>
<Col sm={6}>
<Input type="date" name="date" id="date" value={date} onChange={e=>setDate(e.target.value)}/>
</Col>
</Row>
<br></br>
<Row>
<Label for="gender" sm={3} className="white right">Gender</Label>
<Col md={5} sm={7}>
<RadioButtons gender={gender} setGender={e=>setGender(e.target.value)} />
</Col>
</Row>
</Form>
)
}
Please add filter condition []
useEffect( () => {
axios.get('https://www.memento-wedding.com/user/' + id)
.then(response => {
setProfileData(response.data);
})
console.log(profile.gender);
},[]);
Related
Hey guys ı have some issues react hook form handle submit function doesn't work what is issue can you help ?
const AccountTabs = ({ userDetail }) => {
const { register, handleSubmit } = useForm();
console.log(userDetail)
const onSubmit = (data) => {
alert(JSON.stringify(data));
console.log(data)
}
return (
<Fragment>
<Card>
<CardHeader className='border-bottom'>
<CardTitle tag='h4'>İşletme Ayarları</CardTitle>
</CardHeader>
<CardBody className='py-2 my-25'>
<div className='d-flex'>
<div className='me-25'>
<img className='rounded me-50' alt='İşletmeye ait logo ' height='100' width='100' />
</div>
<div className='d-flex align-items-end mt-75 ms-1'>
<div>
<Button tag={Label} className='mb-75 me-75' size='sm' color='primary'>
Yükle
<Input type='file' hidden accept='image/*' />
</Button>
<Button className='mb-75' color='secondary' size='sm' outline >
Sil
</Button>
<p className='mb-0'> JPG veya PNG türünde yükleme yapınız</p>
</div>
</div>
</div>
<Form className='mt-2 pt-50' onSubmit={(e) => { e.preventDefault(); handleSubmit(onSubmit) }} >
<Row>
<Col sm='6' className='mb-1'>
<Label className='form-label' > Ad Soyadı </Label>
<Input defaultValue={userDetail.name} {...register("name", { required: true })} />
</Col>
<Col sm='6' className='mb-1'>
<Label className='form-label' > Kullanıcı adı </Label>
<Input defaultValue={userDetail.username} {...register("kullanici", { required: true })} />
</Col>
<Col sm='6' className='mb-1'>
<Label className='form-label' > E-mail </Label>
<Input type='email' defaultValue={userDetail.contact.email} {...register("email", { required: true })} />
</Col>
<Col sm='6' className='mb-1'>
<Label className='form-label' > İşletme Adı </Label>
<Input defaultValue={userDetail.companyName} {...register("companyName", { required: true })} />
</Col>
<Col sm='6' className='mb-1'>
<Label className='form-label' > Telefon Numarası </Label>
<Cleave
value={userDetail.contact.phone}
{...register("phone", { required: true })}
className='form-control'
options={{ phone: true, phoneRegionCode: 'TR' }}
/>
</Col>
<Col sm='6' className='mb-1'>
<Label className='form-label' > Adres</Label>
<Input defaultValue={userDetail.contact.address} {...register("address", { required: true })} />
</Col>
<Col className='mt-2' sm='12'>
<input type='submit' className='me-1' value='Kaydet' />
</Col>
</Row>
</Form>
</CardBody>
</Card>
</Fragment>
)
}
export default AccountTabs
form can submit but onSubmit function doesn't work what is problem i am ussed first time react-hook-form library, form can submit but onSubmit function doesn't work what is problem i am ussed first time react-hook-form library,form can submit but onSubmit function doesn't work what is problem i am ussed first time react-hook-form library
handleSubmit fires submit function only when validation is successful, So please see if all the required data is filled when you submit the form ( or handle the validations).
const AccountTabs = ({ userDetail }) => {
const { register, handleSubmit, formState } = useForm();
console.log(userDetail)
const onSubmit = (data) => {
alert(JSON.stringify(data));
console.log(data)
}
// formstate has the errors
console.log(formState.errors);
return (
<Fragment>
//code
</Fragment>
)
}
Check this link for validtions
Creating a function that will update my state based to edit user profile information based on input submitted on a form.
My function is only updating the last input I entered in my form. Here is a snippet of my code
let { user,logOutUser,updateProfile } = useContext(AuthContext)
//store users in state
const[profileUser, setProfileUser] = useState({user})
//handle form submission
const handleSubmit = e => {
console.log(user)
const updatedProfile = {
username: profileUser.username,
email: profileUser.email,
first_name: profileUser.first_name,
last_name: profileUser.last_name,
city: profileUser.city,
country: profileUser.country
}
console.log(updatedProfile)
e.preventDefault();
}
and here's my form:
<Form>
<Row>
<Col className="pr-1" md="6">
<FormGroup>
<label>Username</label>
<Input
placeholder="Username"
type="text"
name="username"
onChange={ e => setProfileUser({'username': e.target.value}) }
/>
</FormGroup>
</Col>
<Col className="pr-1" md="6">
<FormGroup>
<label htmlFor="exampleInputEmail1">
Email address
</label>
<Input
placeholder="Email"
type="email"
name="email"
value={profileUser.email}
onChange={ e => setProfileUser({'email': e.target.value}) }
/>
</FormGroup>
</Col>
</Row>
<Row>
<Col className="pr-1" md="6">
<FormGroup>
<label>First Name</label>
<Input
placeholder="Enter your first name"
type="text"
name="first_name"
onChange={ e => setProfileUser({'first_name': e.target.value}) }
/>
</FormGroup>
</Col>
<Col className="pr-1" md="6">
<FormGroup>
<label>Last Name</label>
<Input
placeholder="Enter your last name"
type="text"
name="last_name"
onChange={ e => setProfileUser({'last_name': e.target.value}) }
/>
</FormGroup>
</Col>
</Row>
<Row>
<Col className="pr-1" md="6">
<FormGroup>
<label>City</label>
<Input
placeholder="Enter your city"
type="text"
name="city"
onChange={ e => setProfileUser({'city': e.target.value}) }
/>
</FormGroup>
</Col>
<Col className="pr-1" md="6">
<FormGroup>
<label>Country</label>
<Input
placeholder="Enter your country"
type="text"
name="country"
onChange={ e => setProfileUser({'country': e.target.value}) }
/>
</FormGroup>
</Col>
<div className="update ml-auto mr-auto">
<Button
className="btn-round"
color="primary"
type="submit"
onClick={handleSubmit}
>
Update Profile
</Button>
</div>
</Row>
</Form>
This is what I have in users:
bio: ""
city: ""
country: ""
exp: *****
first_name: ""
iat: *****
jti: "******"
last_name: ""
photo: "\"profile/2022/03/27/emmanuelpic.png\""
token_type: "access"
user_id: 1
username: "emmanuelS21"
When I console log updateProfile after submitting updated profile data, I am only getting the last input I entered in my form (ie. If I enter last_name, I only see this in my console log while everything else in my object is empty)
Each use of setProfileUser is overwriting the entire object with a new object that contains only one property:
onChange={ e => setProfileUser({'email': e.target.value}) }
You can destructure the current state to build the complete new state:
onChange={ e => setProfileUser({ ...profileUser, 'email': e.target.value}) }
This is notably different from the older setState used in class-based components. With setState the framework would automatically perform partial updates for you. But with the setter function in useState hooks, any update is complete as-is.
when you set the state must add rest of value to new state with {...rest}
onChange={ e => setProfileUser({...profileUser,'username': e.target.value}) }
if i put populate in server side code i am getting error like this Uncaught Error: Objects are not valid as a React child (found: object with keys {_id, name}). If you meant to render a collection of children, use an array instead.
if i remove the populate then code is working fine.
How can i solve this issue ?
My code is
ProductPage.js
import React, { useState } from "react";
import Layout from "../components/Layout/Layout";
import { Container, Row, Col, Table } from "react-bootstrap";
import { useDispatch, useSelector } from "react-redux";
import Input from "../components/UI/Input";
import { addProduct } from "../redux/actions";
import Modal from "../components/UI/Modal";
import "./Home.css";
import { generatePublicurl } from "../urlConfig";
function ProductsPage(props) {
const category = useSelector((state) => state.category);
const product = useSelector((state) => state.product);
const dispatch = useDispatch();
const [show, setShow] = useState(false);
const [productDetailModail, setProductDetailModal] = useState(false);
const [productDetails, setProductDetails] = useState(null);
const [name, setName] = useState("");
const [productPicture, setProductPicture] = useState([]);
const [description, setDescription] = useState("");
const [price, setPrice] = useState("");
const [quantity, setQuantity] = useState("");
const [categoryId, setCategoryId] = useState("");
const handleClose = () => {
const form = new FormData();
form.append("name", name);
form.append("description", description);
form.append("price", price);
form.append("quantity", quantity);
form.append("category", categoryId);
for (let pic of productPicture) {
form.append("productPicture", pic);
}
dispatch(addProduct(form));
setShow(false);
};
const handleShow = () => setShow(true);
const createCategoryList = (categories, options = []) => {
for (let category of categories) {
options.push({ value: category._id, name: category.name });
if (category.children.length > 0) {
createCategoryList(category.children, options);
}
}
console.log(options);
return options;
};
const handleProductPicture = (e) => {
setProductPicture([...productPicture, e.target.files[0]]);
};
const renderProducts = () => {
return (
<Table style={{ fontSize: 12 }} responsive="sm" className="mt-5">
<thead>
<tr>
<th>#</th>
<th>Product Name</th>
<th>Price</th>
<th>Quantity</th>
<th>Category</th>
<th>Created By</th>
</tr>
</thead>
<tbody>
{product.products.length > 0
? product.products.map((product) => (
<tr
key={product._id}
onClick={() => showProductDetailsModal(product)}
>
<td>1</td>
<td>{product.name}</td>
<td>{product.price}</td>
<td>{product.quantity}</td>
<td>{product.category}</td>
<td>{product.createdBy}</td>
</tr>
))
: null}
</tbody>
</Table>
);
};
const renderAddProductModal = () => {
return (
<Modal
show={show}
handleClose={handleClose}
modalTitle={"Add New Product"}
actionName={"Add Product"}
>
<Input
label="Product Name"
vale={name}
placeholder="Product Name"
onChange={(e) => setName(e.target.value)}
/>
<Input
label="Product Price"
vale={price}
placeholder="Product Price"
onChange={(e) => setPrice(e.target.value)}
/>
<Input
label="Product Stock"
vale={quantity}
placeholder="Product Stock"
onChange={(e) => setQuantity(e.target.value)}
/>
<Input
label="Product Description"
vale={description}
placeholder="Product Description"
onChange={(e) => setDescription(e.target.value)}
/>
<select
value={categoryId}
className="form-control"
onChange={(e) => setCategoryId(e.target.value)}
>
<option>Select Category</option>
{createCategoryList(category.categories).map((option) => (
<option value={option.value} key={option.value}>
{option.name}
</option>
))}
</select>
{productPicture.length > 0 &&
productPicture.map((pic, index) => <div key={index}>{pic.name}</div>)}
<input
className="mt-3"
type={"file"}
name="productPicture"
onChange={handleProductPicture}
/>
</Modal>
);
};
const handleCloseProductDetailModal = () => {
setProductDetailModal(false);
};
const showProductDetailsModal = (product) => {
setProductDetails(product);
setProductDetailModal(true);
};
const renderProductDetailsModal = () => {
if (!productDetails) {
return null;
}
return (
<Modal
size="lg"
show={productDetailModail}
handleClose={handleCloseProductDetailModal}
modalTitle={"Product Details"}
actionName={"Save Changes"}
>
<Row>
<Col md="6">
<label className="key">Product Name</label>
<p className="value">{productDetails.name}</p>
</Col>
<Col md="6">
<label className="key">Product Price</label>
<p className="value">{productDetails.price}</p>
</Col>
</Row>
<Row>
<Col md="6">
<label className="key">Product Quantity</label>
<p className="value">{productDetails.quantity}</p>
</Col>
<Col md="6">
<label className="key">Product Category</label>
<p className="value">{productDetails.category}</p>
</Col>
</Row>
<Row>
<Col>
<label className="key">Product Description</label>
<p className="value">{productDetails.description}</p>
</Col>
</Row>
<Row>
<Col>
<label className="key mb-3">Product Images</label>
<div style={{ display: "flex" }}>
{productDetails.productPictures.map((picture) => (
<div className="productImageContainer ">
<img src={generatePublicurl(picture.img)} />
</div>
))}
</div>
</Col>
</Row>
</Modal>
);
};
return (
<Layout sidebar>
<Container>
<Row>
<Col md={12}>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<h3>Products</h3>
<button onClick={handleShow}>Add Product</button>
</div>
</Col>
</Row>
<Row>
<Col>{renderProducts()}</Col>
</Row>
{renderAddProductModal()}
{renderProductDetailsModal()}
</Container>
</Layout>
);
}
export default ProductsPage;
initialData.js
const Product = require("../../models/product");
const Category = require("../../models/category");
function createCategories(categories, parentId = null) {
const categoryList = [];
let category;
if (parentId == null) {
category = categories.filter((cat) => cat.parentId == undefined);
} else {
category = categories.filter((cat) => cat.parentId == parentId);
}
for (let cate of category) {
categoryList.push({
_id: cate._id,
name: cate.name,
slug: cate.slug,
parentId: cate.parentId,
children: createCategories(categories, cate._id),
});
}
return categoryList;
}
exports.initialData = async (req, res) => {
const categories = await Category.find({}).exec();
const products = await Product.find({})
.select(
"_id name slug price quantity category createdBy description productPictures"
)
.populate({ path: "category", select: "_id name" })
.exec();
res.status(200).json({
categories: createCategories(categories),
products,
});
};
For ref please find the attached image also.
I have to replace this {product.category} with {product.category.name}
populate is giving an object so i am getting this error after calling name is this object problem is resolved.
import React, { useState } from "react";
import Layout from "../components/Layout/Layout";
import { Container, Row, Col, Table } from "react-bootstrap";
import { useDispatch, useSelector } from "react-redux";
import Input from "../components/UI/Input";
import { addProduct } from "../redux/actions";
import Modal from "../components/UI/Modal";
import "./Home.css";
import { generatePublicurl } from "../urlConfig";
function ProductsPage(props) {
const category = useSelector((state) => state.category);
const product = useSelector((state) => state.product);
const dispatch = useDispatch();
const [show, setShow] = useState(false);
const [productDetailModail, setProductDetailModal] = useState(false);
const [productDetails, setProductDetails] = useState(null);
const [name, setName] = useState("");
const [productPicture, setProductPicture] = useState([]);
const [description, setDescription] = useState("");
const [price, setPrice] = useState("");
const [quantity, setQuantity] = useState("");
const [categoryId, setCategoryId] = useState("");
const handleClose = () => {
const form = new FormData();
form.append("name", name);
form.append("description", description);
form.append("price", price);
form.append("quantity", quantity);
form.append("category", categoryId);
for (let pic of productPicture) {
form.append("productPicture", pic);
}
dispatch(addProduct(form));
setShow(false);
};
const handleShow = () => setShow(true);
const createCategoryList = (categories, options = []) => {
for (let category of categories) {
options.push({ value: category._id, name: category.name });
if (category.children.length > 0) {
createCategoryList(category.children, options);
}
}
console.log(options);
return options;
};
const handleProductPicture = (e) => {
setProductPicture([...productPicture, e.target.files[0]]);
};
const renderProducts = () => {
return (
<Table style={{ fontSize: 12 }} responsive="sm" className="mt-5">
<thead>
<tr>
<th>#</th>
<th>Product Name</th>
<th>Price</th>
<th>Quantity</th>
<th>Category</th>
<th>Created By</th>
</tr>
</thead>
<tbody>
{product.products.length > 0
? product.products.map((product) => (
<tr
key={product._id}
onClick={() => showProductDetailsModal(product)}
>
<td>1</td>
<td>{product.name}</td>
<td>{product.price}</td>
<td>{product.quantity}</td>
<td>{product.category}</td>
<td>{product.createdBy}</td>
</tr>
))
: null}
</tbody>
</Table>
);
};
const renderAddProductModal = () => {
return (
<Modal
show={show}
handleClose={handleClose}
modalTitle={"Add New Product"}
actionName={"Add Product"}
>
<Input
label="Product Name"
vale={name}
placeholder="Product Name"
onChange={(e) => setName(e.target.value)}
/>
<Input
label="Product Price"
vale={price}
placeholder="Product Price"
onChange={(e) => setPrice(e.target.value)}
/>
<Input
label="Product Stock"
vale={quantity}
placeholder="Product Stock"
onChange={(e) => setQuantity(e.target.value)}
/>
<Input
label="Product Description"
vale={description}
placeholder="Product Description"
onChange={(e) => setDescription(e.target.value)}
/>
<select
value={categoryId}
className="form-control"
onChange={(e) => setCategoryId(e.target.value)}
>
<option>Select Category</option>
{createCategoryList(category.categories).map((option) => (
<option value={option.value} key={option.value}>
{option.name}
</option>
))}
</select>
{productPicture.length > 0 &&
productPicture.map((pic, index) => <div key={index}>{pic.name}</div>)}
<input
className="mt-3"
type={"file"}
name="productPicture"
onChange={handleProductPicture}
/>
</Modal>
);
};
const handleCloseProductDetailModal = () => {
setProductDetailModal(false);
};
const showProductDetailsModal = (product) => {
setProductDetails(product);
setProductDetailModal(true);
};
const renderProductDetailsModal = () => {
if (!productDetails) {
return null;
}
return (
<Modal
size="lg"
show={productDetailModail}
handleClose={handleCloseProductDetailModal}
modalTitle={"Product Details"}
actionName={"Save Changes"}
>
<Row>
<Col md="6">
<label className="key">Product Name</label>
<p className="value">{productDetails.name}</p>
</Col>
<Col md="6">
<label className="key">Product Price</label>
<p className="value">{productDetails.price}</p>
</Col>
</Row>
<Row>
<Col md="6">
<label className="key">Product Quantity</label>
<p className="value">{productDetails.quantity}</p>
</Col>
<Col md="6">
<label className="key">Product Category</label>
<p className="value">{productDetails.category}</p>
</Col>
</Row>
<Row>
<Col>
<label className="key">Product Description</label>
<p className="value">{productDetails.description}</p>
</Col>
</Row>
<Row>
<Col>
<label className="key mb-3">Product Images</label>
<div style={{ display: "flex" }}>
{productDetails.productPictures.map((picture) => (
<div className="productImageContainer ">
<img src={generatePublicurl(picture.img)} />
</div>
))}
</div>
</Col>
</Row>
</Modal>
);
};
return (
<Layout sidebar>
<Container>
<Row>
<Col md={12}>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<h3>Products</h3>
<button onClick={handleShow}>Add Product</button>
</div>
</Col>
</Row>
<Row>
<Col>{renderProducts()}</Col>
</Row>
{renderAddProductModal()}
{renderProductDetailsModal()}
</Container>
</Layout>
);
}
export default ProductsPage;
I am a beginner in reactJS and would like to ask a simple question. I am following some tutorials and I really don't know why this wont work on mine. I know my question is very simple since I am a beginner. Please have a patience with my question.
I have this code from a function component form:
function Login() {
const emailInputRef = useRef();
const passwordInputRef = useRef();
function submitHandler(e) {
e.preventDefault();
const emailInput = emailInputRef.current.value;
const passwordInput = passwordInputRef.current.value;
console.log(emailInput);
}
return (
<>
<Col lg="5" md="7">
<Card className="bg-secondary shadow border-0">
<CardBody className="px-lg-5 py-lg-5">
<div className="text-center text-muted mb-4">
<small>Sign in</small>
</div>
<Form role="form" onSubmit={submitHandler}>
<FormGroup className="mb-3">
<InputGroup className="input-group-alternative">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="ni ni-email-83" />
</InputGroupText>
</InputGroupAddon>
<Input
placeholder="Email"
type="email"
autoComplete="new-email"
ref={emailInputRef}
/>
</InputGroup>
</FormGroup>
<FormGroup>
<InputGroup className="input-group-alternative">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="ni ni-lock-circle-open" />
</InputGroupText>
</InputGroupAddon>
<Input
placeholder="Password"
type="password"
autoComplete="new-password"
ref={passwordInputRef}
/>
</InputGroup>
</FormGroup>
<div className="custom-control custom-control-alternative custom-checkbox">
<input
className="custom-control-input"
id=" customCheckLogin"
type="checkbox"
/>
<label
className="custom-control-label"
htmlFor=" customCheckLogin"
>
<span className="text-muted">Remember me</span>
</label>
</div>
<div className="text-center">
<Button className="my-4" color="primary" type="submit">
Sign in
</Button>
</div>
</Form>
</CardBody>
</Card>
<Row className="mt-3">
<Col xs="6">
<a
className="text-light"
href="#pablo"
onClick={(e) => e.preventDefault()}
>
<small>Forgot password?</small>
</a>
</Col>
<Col className="text-right" xs="6">
<a
className="text-light"
href="#pablo"
onClick={(e) => e.preventDefault()}
>
<small>Create new account</small>
</a>
</Col>
</Row>
</Col>
</>
);
}
I want to bind my input type from my submitHandler and log the values of the input types. I followed a tutorial using refs and I don't know if I made something wrong about it since I was a beginner. When I logged the values it gives me undefined values.
To get the current input reference use innerRef property instead of ref:
<Input
placeholder="Email"
type="email"
autoComplete="new-email"
innerRef={emailInputRef}
/>
const emailInput = emailInputRef.current.value;
ref will only get you a reference to the Input component, innerRef will get you a reference to the DOM input.
You have a few options for that. You can use the useRef React hook or the state stored using the useState React Hook. In both cases you need to import the related hook first. You could use both if you want. You could also use a custom hook with the useReducer React hook.
In your case it would be something like these:
Option # 1: Using useRef
import {useRef} from "react";
function Login() {
const emailInputRef = useRef();
const passwordInputRef = useRef();
function submitFormHandler(event) {
event.preventDefault();
const email = emailInputRef.current.value;
const password = passwordInputRef.current.value;
console.log(`email = ${email} & password = ${password}`);
}
return (
<>
<Col lg="5" md="7">
<Card className="bg-secondary shadow border-0">
<CardBody className="px-lg-5 py-lg-5">
<div className="text-center text-muted mb-4">
<small>Sign in</small>
</div>
<Form role="form" onSubmit={submitFormHandler}>
<FormGroup className="mb-3">
<InputGroup className="input-group-alternative">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="ni ni-email-83"/>
</InputGroupText>
</InputGroupAddon>
<Input
placeholder="Email"
type="email"
id='email'
name='email'
required
autoComplete="new-email"
ref={emailInputRef}
/>
</InputGroup>
</FormGroup>
<FormGroup>
<InputGroup className="input-group-alternative">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="ni ni-lock-circle-open"/>
</InputGroupText>
</InputGroupAddon>
<input
placeholder="Password"
type="password"
id="password"
name="password"
required
autoComplete="new-password"
ref={passwordInputRef}
/>
</InputGroup>
</FormGroup>
<div className="custom-control custom-control-alternative custom-checkbox">
<input
className="custom-control-input"
id=" customCheckLogin"
type="checkbox"
/>
<label
className="custom-control-label"
htmlFor=" customCheckLogin"
>
<span className="text-muted">Remember me</span>
</label>
</div>
<div className="text-center">
<Button className="my-4" color="primary" type="submit">
Sign in
</Button>
</div>
</Form>
</CardBody>
</Card>
<Row className="mt-3">
<Col xs="6">
<a
className="text-light"
href="#pablo"
onClick={(e) => e.preventDefault()}
>
<small>Forgot password?</small>
</a>
</Col>
<Col className="text-right" xs="6">
<a
className="text-light"
href="#pablo"
onClick={(e) => e.preventDefault()}
>
<small>Create new account</small>
</a>
</Col>
</Row>
</Col>
</>
);
};
export default Login;
Option # 2: Using useState
import {useState} from "react";
function Login() {
const [emailState, setEmailState] = useState('');
const [passwordState, setPasswordState] = useState('');
function submitFormHandler(event) {
event.preventDefault();
console.log(`email = ${emailState} & password = ${passwordState}`);
}
const onEmailChangeHandler = (event) => {
setEmailState(event.current.value);
};
const onPasswordChangeHandler = (event) => {
setPasswordState(event.current.value);
};
return (
<>
<Col lg="5" md="7">
<Card className="bg-secondary shadow border-0">
<CardBody className="px-lg-5 py-lg-5">
<div className="text-center text-muted mb-4">
<small>Sign in</small>
</div>
<Form role="form" onSubmit={submitFormHandler}>
<FormGroup className="mb-3">
<InputGroup className="input-group-alternative">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="ni ni-email-83"/>
</InputGroupText>
</InputGroupAddon>
<input
placeholder="Email"
type="email"
id='email'
name='email'
required
autoComplete="new-email"
value={emailState}
onChange={onEmailChangeHandler}
/>
</InputGroup>
</FormGroup>
<FormGroup>
<InputGroup className="input-group-alternative">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="ni ni-lock-circle-open"/>
</InputGroupText>
</InputGroupAddon>
<input
placeholder="Password"
type="password"
id="password"
name="password"
required
autoComplete="new-password"
value={passwordState}
onChange={onPasswordChangeHandler}
/>
</InputGroup>
</FormGroup>
<div className="custom-control custom-control-alternative custom-checkbox">
<input
className="custom-control-input"
id=" customCheckLogin"
type="checkbox"
/>
<label
className="custom-control-label"
htmlFor=" customCheckLogin"
>
<span className="text-muted">Remember me</span>
</label>
</div>
<div className="text-center">
<Button className="my-4" color="primary" type="submit">
Sign in
</Button>
</div>
</Form>
</CardBody>
</Card>
<Row className="mt-3">
<Col xs="6">
<a
className="text-light"
href="#pablo"
onClick={(e) => e.preventDefault()}
>
<small>Forgot password?</small>
</a>
</Col>
<Col className="text-right" xs="6">
<a
className="text-light"
href="#pablo"
onClick={(e) => e.preventDefault()}
>
<small>Create new account</small>
</a>
</Col>
</Row>
</Col>
</>
);
};
export default Login;
Option # 3: Using both React hooks (useRef & useState).
You could use the useRef React hook for focusing purposes only and also use a local state value, using the useState React hook, for the usual purposes of login in.
Option # 4: Using custom hooks.
You can use all the mentioned before, but using primordially a custom hook, which uses the useReducer React hook under the trunk, and then useRef for focusing and useState for other purposes:
Coder example:
Custom hook:
import {useReducer} from "react";
const initialInputState = {
valueState: '',
valueIsTouchedState: false,
};
const inputStateReducer = (state, action) => {
if (action.type === 'SET_VALUE_IS_TOUCHED_STATE') {
return {
valueState: state.valueState,
valueIsTouchedState: action.payload.valueIsTouchedState
};
}
if (action.type === 'SET_VALUE_STATE') {
return {
valueState: action.payload.valueState,
valueIsTouchedState: state.valueIsTouchedState
};
}
return initialInputState;
};
const useInputReducer = (valueValidator) => {
const [inputState, dispatchFunction] = useReducer(inputStateReducer, initialInputState);
const valueIsValidState = valueValidator(inputState.valueState);
const valueInputIsInvalid = (!valueIsValidState && inputState.valueIsTouchedState);
const valueInputChangeHandler = (event) => {
dispatchFunction({type: 'SET_VALUE_IS_TOUCHED_STATE', payload: {valueIsTouchedState: true}});
dispatchFunction({type: 'SET_VALUE_STATE', payload: {valueState: event.target.value}});
};
const valueInputBlurHandler = (event) => {
dispatchFunction({type: 'SET_VALUE_IS_TOUCHED_STATE', payload: {valueIsTouchedState: true}});
// setValueState(event.target.value);
};
const setValueIsTouchedState = (value) => {
dispatchFunction({type: 'SET_VALUE_IS_TOUCHED_STATE', payload: {valueIsTouchedState: value}});
};
const resetValueInput = () => {
dispatchFunction({type: 'SET_VALUE_STATE', payload: {valueState: ''}});
dispatchFunction({type: 'SET_VALUE_IS_TOUCHED_STATE', payload: {valueIsTouchedState: false}});
};
return {
valueState: inputState.valueState,
setValueIsTouchedState,
valueIsValidState,
valueInputIsInvalid,
valueInputChangeHandler,
valueInputBlurHandler,
resetValueInput,
};
};
export default useInputReducer;
Form:
import {Fragment, useRef, useState} from 'react';
import {Prompt} from "react-router-dom";
import useInputReducer from "../../hooks/use-input-reducer";
import * as validators from "../../tools/validators";
import styles from './AuthForm.module.css';
const AuthForm = () => {
const [isLogin, setIsLogin] = useState(true);
const [startedToWork, setStartedToWork] = useState(false);
const {
valueState: emailState,
setValueIsTouchedState: setEmailIsTouchedState,
valueIsValidState: emailIsValidState, valueInputIsInvalid: emailInputIsInvalid,
valueInputChangeHandler: emailInputChangeHandler,
// valueInputBlurHandler: emailInputBlurHandler,
resetValueInput: resetEmailInput,
} = useInputReducer(validators.emailValidator);
const {
valueState: passwordState,
setValueIsTouchedState: setPasswordIsTouchedState,
valueIsValidState: passwordIsValidState, valueInputIsInvalid: passwordInputIsInvalid,
valueInputChangeHandler: passwordInputChangeHandler,
// valueInputBlurHandler: passwordInputBlurHandler,
resetValueInput: resetPasswordInput,
} = useInputReducer(validators.nameValidator);
const formIsValid = (emailIsValidState && passwordIsValidState);
const emailInputRef = useRef();
const passwordInputRef = useRef();
const submitFormHandler = (event) => {
event.preventDefault();
setEmailIsTouchedState(true);
setPasswordIsTouchedState(true);
emailInputRef.current.focus();
if (!formIsValid) {
setProperFocus();
return;
}
console.log('Submitted!. I did something!!');
const email = emailInputRef.current.value;
const password = passwordInputRef.current.value;
resetEmailInput();
resetPasswordInput();
};
const setProperFocus = () => {
if (emailInputIsInvalid) {
emailInputRef.current.focus();
} else if (passwordInputIsInvalid) {
passwordInputRef.current.focus();
}
}
const switchAuthModeHandler = () => {
setIsLogin((prevState) => !prevState);
};
const onStartedToWorkHandler = () => {
setStartedToWork(true);
};
const onFinishEnteringHandler = () => {
setStartedToWork(false);
};
const emailValidityClasses = `${styles.control}${emailInputIsInvalid ? ` ${styles.invalid}` : ''}`;
const passwordValidityClasses = `${styles.control}${passwordInputIsInvalid ? ` ${styles.invalid}` : ''}`;
return (
<Fragment>
<Prompt
when={startedToWork}
message={location =>
`Are you sure you want to go to "${location.pathname}"? \n All your entered data will be lost.`
}
/>
<section className={styles.auth}>
<h1>{isLogin ? 'Login' : 'Sign Up'}</h1>
<form
onSubmit={submitFormHandler}
onChange={onStartedToWorkHandler}
>
<div className={emailValidityClasses}>
<label htmlFor='email'>Your Email</label>
<input
type='email'
id='email'
name='email'
required
autoFocus={true}
ref={emailInputRef}
value={emailState}
onChange={emailInputChangeHandler}
// onBlur={emailInputBlurHandler}
/>
{emailInputIsInvalid ? <p className={styles['error-text']}>The Email must be valid.</p> : <p> </p>}
</div>
<div className={passwordValidityClasses}>
<label htmlFor='password'>Your Password</label>
<input
type='password'
id='password'
required
autoComplete="on"
ref={passwordInputRef}
value={passwordState}
onChange={passwordInputChangeHandler}
// onBlur={passwordInputBlurHandler}
/>
{passwordInputIsInvalid ? <p className={styles['error-text']}>The Password must not be empty.</p> : <p> </p>}
</div>
<div className={styles.actions}>
<button onClick={onFinishEnteringHandler}>{isLogin ? 'Login' : 'Create Account'}</button>
<button
type='button'
className={styles.toggle}
onClick={switchAuthModeHandler}
>
{isLogin ? 'Create new account' : 'Login with existing account'}
</button>
</div>
</form>
</section>
</Fragment>
);
};
export default AuthForm;
I never do react js but i code react native.
I think you can store the input in the state using onChangeText like this
using hooks
const index = ()=>{
const {state,setState} = useState('');
return <TextInput onChangeText={(txt)=>{
setState(txt);
console.log(state); }} />
}
So this may be something simple but I'm hitting a roadblock. I want to take in a form input but can't seem to figure out how to append the value correctly so its appending string is captured.
I'm using Formik with yup in react.
<InputGroup>
<Field
id="appended-input"
name="domain_url"
type="text"
value={values.domain_url}
className={
"form-control" +
(errors.domain_url && touched.domain_url
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="domain_url"
component="div"
className="invalid-feedback"
/>
<InputGroupAddon addonType="append">
.localhost
</InputGroupAddon>
</InputGroup>
Any help would be appreciated. I just want to get the .localhost to be automatically added to the input items. for this field. I thought I could do something like value=({values.domain_url} + ".localhost") but that didn't seem to work and as you may already tell I am very new to javascript.
Thank you!
Full code below, I'm also having issues with datepicker displaying within the formik state, and then there's how to even get the values to push to my getTenant(function) to be passed to my api.
static propTypes = {
addTenant: PropTypes.func.isRequired,
};
onSubmit = (values) => {
values.preventDefault();
this.props.addTenant(values);
};
render() {
const {
domain_url,
schema_name,
name,
config,
} = this.state;
const TenantSchema = Yup.object().shape({
domain_url: Yup.string()
.max(255, "Must be shorter than 255 characters")
.required("Client URL header is required"),
schema_name: Yup.string()
.max(255, "Must be shorter than 255 characters")
.required("Client db name is required"),
name: Yup.string()
.max(255, "Must be shorter than 255 characters")
.required("Client name is required"),
});
return (
<div className={s.root}>
<Formik
initialValues={{
domain_url: "",
schema_name: "",
client_name: "",
config: [
{
date: "",
Tenant_description: "",
},
],
}}
// validationSchema={TenantSchema} this is commented off because it breaks
submittions
onSubmit={(values, { setSubmitting, resetForm }) => {
setSubmitting(true);
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
resetForm();
setSubmitting(false);
}, 100);
}}
//onSubmit={onSubmit}
>
{({
values,
errors,
status,
touched,
handleBlur,
handleChange,
isSubmitting,
setFieldValue,
handleSubmit,
props,
}) => (
<FormGroup>
<Form onSubmit={handleSubmit}>
<legend>
<strong>Create</strong> Tenant
</legend>
<FormGroup row>
<Label for="normal-field" md={4} className="text-md-right">
Show URL
</Label>
<Col md={7}>
<InputGroup>
<Field
id="appended-input"
name="domain_url"
type="text"
value={values.domain_url}
onSubmit={(values) => {
values.domain_url = values.domain_url + ".localhost";
}} //this isn't working
className={
"form-control" +
(errors.domain_url && touched.domain_url
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="domain_url"
component="div"
className="invalid-feedback"
/>
<InputGroupAddon addonType="append">
.localhost
</InputGroupAddon>
</InputGroup>
</Col>
</FormGroup>
<FormGroup row>
<Label for="normal-field" md={4} className="text-md-right">
Database Name
</Label>
<Col md={7}>
<Field
name="schema_name"
type="text"
className={
"form-control" +
(errors.schema_name && touched.schema_name
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="schema_name"
component="div"
className="invalid-feedback"
/>
</Col>
</FormGroup>
<FormGroup row>
<Label for="normal-field" md={4} className="text-md-right">
Name
</Label>
<Col md={7}>
<Field
name="name"
type="text"
className={
"form-control" +
(errors.name && touched.name
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="name"
component="div"
className="invalid-feedback"
/>
</Col>
</FormGroup>
<FieldArray
name="config"
render={(arrayHelpers) => (
<div>
{values.config.map((config, index) => (
<div key={index}>
<FormGroup row>
<Label
md={4}
className="text-md-right"
for="mask-date"
>
Tenant Description
</Label>
<Col md={7}>
<TextareaAutosize
rows={3}
name={`config.${index}.tenant_description`}
id="elastic-textarea"
type="text"
onReset={values.event_description}
placeholder="Quick description of tenant"
onChange={handleChange}
value={values.tenant_description}
onBlur={handleBlur}
className={
`form-control ${s.autogrow} transition-height` +
(errors.tenant_description &&
touched.tenant_description
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="tenant_description"
component="div"
className="invalid-feedback"
/>
</Col>
</FormGroup>
<FormGroup row>
<Label
for="normal-field"
md={4}
className="text-md-right"
>
Date
</Label>
<Col md={7}>
<DatePicker
tag={Field}
name={`config.${index}.date`}
type="date"
selected={values.date}
value={values.date}
className={
"form-control" +
(errors.date&& touched.date
? " is-invalid"
: "")
}
onChange={(e) =>
setFieldValue("date", e)
}
/>
<ErrorMessage
name="date"
component="div"
className="invalid-feedback"
/>
</Col>
</FormGroup>
</div>
))}
</div>
)}
/>
<div className="form-group">
<button
type="submit"
disabled={isSubmitting}
className="btn btn-primary mr-2"
>
Save Tenant
</button>
<button type="reset" className="btn btn-secondary">
Reset
</button>
</div>
</Form>
<Col md={7}>{JSON.stringify(values)}</Col>
</FormGroup>
)}
</Formik>
</div>
);
}
}
export default connect(null, { addTenant })(TenantForm);
You could use setFieldValue if you want to customize the value
https://jaredpalmer.com/formik/docs/api/formik#setfieldvalue-field-string-value-any-shouldvalidate-boolean--void
You can add onChange
<Field
id="appended-input"
name="domain_url"
type="text"
value={values.domain_url}
onChange={st => {
let value = st.target.value;
let suffix = ".localhost";
let index = value.indexOf(".localhost");
if (index > 0) {
suffix = "";
}
//add suffix 'localhost' if it is not already added
props.setFieldValue("domain_url", value + suffix);
}}
className={
"form-control" +
(errors.domain_url && touched.domain_url ? " is-invalid" : "")
}
/>;
But adding suffix is more preferable on onSubmit:
onSubmit = {(values, actions) => {
console.log('valuesbefore',values)
values.domain_url= values.domain_url+ ".localhost"
console.log('valuesafter',values)
this.props.addTenant(values);
};